Flex, versi≤n 2.5

Un generador de analizadores lΘxicos rßpidos.

Edici≤n 2.5, Abril 1995

Vern Paxson


Table of Contents


@catcode`┐=@active@def┐{@questiondown{}} @catcode`í=@active@defí{@exclamdown{}} @catcode`ß=@active@defß{'a} @catcode`Θ=@active@defΘ{'e} @catcode`φ=@active@defφ{'{@char16{}}} @catcode`≤=@active@def≤{'o} @catcode`·=@active@def·{'u} @catcode`┴=@active@def┴{'A} @catcode`╔=@active@def╔{'E} @catcode`═=@active@def═{'I} @catcode`╙=@active@def╙{'O} @catcode`┌=@active@def┌{'U} @catcode`ⁿ=@active@defⁿ{@"u} @catcode`▄=@active@def▄{@"U} @catcode`±=@active@def±{@~n} @catcode`╤=@active@def╤{@~N} @catcode`¬=@active@def¬{a.}

@gdef@putwordChapter{Capφtulo} @def@putwordInfo{Info} @gdef@putwordSee{Ver} @gdef@putwordsee{ver} @gdef@putwordfile{archivo} @gdef@putwordpage{pßgina} @gdef@putwordsection{secci≤n} @gdef@putwordSection{Secci≤n} @gdef@putwordTableofContents{Tabla de Contenido} @gdef@putwordTOC{Tabla de Contenido} @gdef@putwordShortContents{Contenido Breve} @gdef@putwordAppendix{ApΘndice}

@def@ingles{0} @def@espanol{1}

@language=@espanol

@language=@ingles Copyright (C) 1990 The Regents of the University of California. All rights reserved.

This code is derived from software contributed to Berkeley by Vern Paxson.

The United States Government has rights in this work pursuant to contract no. DE-AC03-76SF00098 between the United States Department of Energy and the University of California.

Redistribution and use in source and binary forms with or without modification are permitted provided that: (1) source distributions retain this entire copyright notice and comment, and (2) distributions including binaries display the following acknowledgement: "This product includes software developed by the University of California, Berkeley and its contributors" in the documentation or other materials provided with the distribution and in all advertising materials mentioning features or use of this software. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. @language=@espanol

Introducci≤n

Este manual describe flex, una herramienta para la generaci≤n de programas que realizan concordancia de patrones en texto. El manual incluye a la vez secciones de tutorial y de referencia:

Descripci≤n
una breve introducci≤n a la herramienta
Algunos Ejemplos Simples
Formato del Fichero de Entrada
Patrones
las expresiones regulares extendidas que utiliza flex
C≤mo se Empareja la Entrada
las reglas para determinar lo que ha concordado
Acciones
c≤mo especificar quΘ hacer cuando concuerde un patr≤n
El Escßner Generado
detalles respecto al escßner que produce flex; c≤mo controlar la fuente de entrada
Condiciones de Arranque
la introduci≤n de contexto en sus escßneres, y conseguir "mini-escßneres"
M·ltiples Buffers de Entrada
c≤mo manipular varias fuentes de entrada; c≤mo analizar cadenas en lugar de ficheros.
Reglas de Fin-de-Fichero
reglas especiales para reconocer el final de la entrada
Macros Miscelßneas
un sumario de macros disponibles para las acciones
Valores Disponibles para el Usuario
un sumario de valores disponibles para las acciones
Interfaz con Yacc
conectando escßneres de flex junto con analizadores de yacc
Opciones
opciones de lφnea de comando de flex, y la directiva "%option"
Consideraciones de Rendimiento
c≤mo hacer que sus analizadores vayan tan rßpido como sea posible
Generando Escßneres en C++
la facilidad (experimental) para generar analizadores lΘxicos como clases de C++
Incompatibilidades con Lex y POSIX
c≤mo flex difiere del lex de AT&T y del lex estßndar de POSIX
Diagn≤sticos
esos mensajes de error producidos por flex (o por los escßneres que este genera) cuyo significado podrφa no ser evidente
Ficheros
los ficheros usados por flex
Deficiencias / Errores
problemas de flex conocidos
Ver TambiΘn
otra documentaci≤n, herramientas relacionadas
Autor
incluye informaci≤n de contacto

Descripci≤n

flex es una herramienta para generar escßneres: programas que reconocen patrones lΘxicos en un texto. flex lee los ficheros de entrada dados, o la entrada estßndar si no se le ha indicado ning·n nombre de fichero, con la descripci≤n de un escßner a generar. La descripci≤n se encuentra en forma de parejas de expresiones regulares y c≤digo C, denominadas reglas. flex genera como salida un fichero fuente en C, `lex.yy.c', que define una rutina `yylex()'. Este fichero se compila y se enlaza con la librerφa `-lfl' para producir un ejecutable. Cuando se arranca el fichero ejecutable, este analiza su entrada en busca de casos de las expresiones regulares. Siempre que encuentra uno, ejecuta el c≤digo C correspondiente.

Algunos ejemplos simples

En primer lugar veremos algunos ejemplos simples para una toma de contacto con el uso de flex. La siguiente entrada de flex especifica un escßner que siempre que encuentre la cadena "username" la reemplazarß por el nombre de entrada al sistema del usuario:

%%
username    printf( "%s", getlogin() );

Por defecto, cualquier texto que no reconozca el analizador lΘxico de flex se copia a la salida, asφ que el efecto neto de este escßner es copiar su fichero de entrada a la salida con cada aparici≤n de "username" expandida. En esta entrada, hay solamente una regla. "username" es el patr≤n y el "printf" es la acci≤n. El "%%" marca el comienzo de las reglas.

Aquφ hay otro ejemplo simple:

        int num_lineas = 0, num_caracteres = 0;

%%
\n      ++num_lineas; ++num_caracteres;
.       ++num_caracteres;

%%
main()
        {
        yylex();
        printf( "# de lφneas = %d, # de caracteres. = %d\n",
                num_lineas, num_caracteres );
        }

Este analizador cuenta el n·mero de caracteres y el n·mero de lφneas en su entrada (no produce otra salida que el informe final de la cuenta). La primera lφnea declara dos variables globales, "num_lineas" y "num_caracteres", que son visibles al mismo tiempo dentro de `yylex()' y en la rutina `main()' declarada despuΘs del segundo "%%". Hay dos reglas, una que empareja una lφnea nueva ("\n") e incrementa la cuenta de lφneas y la cuenta de caracteres, y la que empareja cualquier caracter que no sea una lφnea nueva (indicado por la expresi≤n regular ".").

Un ejemplo algo mßs complicado:

/* escßner para un lenguaje de juguete al estilo de Pascal */

%{
/* se necesita esto para la llamada a atof() mßs abajo */
#include <math.h>
%}

DIGITO   [0-9]
ID       [a-z][a-z0-9]*

%%

{DIGITO}+   {
            printf( "Un entero: %s (%d)\n", yytext,
                    atoi( yytext ) );
            }

{DIGITO}+"."{DIGITO}*      {
            printf( "Un real: %s (%g)\n", yytext,
                    atof( yytext ) );
            }

if|then|begin|end|procedure|function        {
            printf( "Una palabra clave: %s\n", yytext );
            }

{ID}        printf( "Un identificador: %s\n", yytext );

"+"|"-"|"*"|"/"   printf( "Un operador: %s\n", yytext );

"{"[^}\n]*"}"     /* se come una linea de comentarios */

[ \t\n]+          /* se come los espacios en blanco */

.           printf( "Caracter no reconocido: %s\n", yytext );

%%

main( argc, argv )
int argc;
char **argv;
    {
    ++argv, --argc;  /* se salta el nombre del programa */
    if ( argc > 0 )
            yyin = fopen( argv[0], "r" );
    else
            yyin = stdin;
    
    yylex();
    }

Esto podrφa ser los comienzos de un escßner simple para un lenguaje como Pascal. Este identifica diferentes tipos de tokens e informa a cerca de lo que ha visto.

Los detalles de este ejemplo se explicarßn en las secciones siguientes.

Formato del fichero de entrada

El fichero de entrada de flex estß compuesto de tres secciones, separadas por una lφnea donde aparece ·nicamente un `%%' en esta:

definiciones
%%
reglas
%%
c≤digo de usuario

La secci≤n de definiciones contiene declaraciones de definiciones de nombres sencillas para simplificar la especificaci≤n del escßner, y declaraciones de condiciones de arranque, que se explicarßn en una secci≤n posterior. Las definiciones de nombre tienen la forma:

nombre definici≤n

El "nombre" es una palabra que comienza con una letra o un subrayado (`_') seguido por cero o mßs letras, dφgitos, `_', o `-' (gui≤n). La definici≤n se considera que comienza en el primer caracter que no sea un espacio en blanco siguiendo al nombre y continuando hasta el final de la lφnea. Posteriormente se puede hacer referencia a la definici≤n utilizando "{nombre}", que se expandirß a "(definici≤n)". Por ejemplo,

DIGITO   [0-9]
ID       [a-z][a-z0-9]*

define "DIGITO" como una expresi≤n regular que empareja un dφgito sencillo, e "ID" como una expresi≤n regular que empareja una letra seguida por cero o mßs letras o dφgitos. Una referencia posterior a

{DIGITO}+"."{DIGITO}*

es idΘntica a

([0-9])+"."([0-9])*

y empareja uno o mßs dφgitos seguido por un `.' seguido por cero o mßs dφgitos.

La secci≤n de reglas en la entrada de flex contiene una serie de reglas de la forma:

patr≤n   acci≤n

donde el patr≤n debe estar sin sangrar y la acci≤n debe comenzar en la misma lφnea.

See section Acciones, para una descripci≤n mßs amplia sobre patrones y acciones.

Finalmente, la secci≤n de c≤digo de usuario simplemente se copia a `lex.yy.c' literalmente. Esta secci≤n se utiliza para rutinas de complemento que llaman al escßner o son llamadas por este. La presencia de esta secci≤n es opcional; Si se omite, el segundo `%%' en el fichero de entrada se podrφa omitir tambiΘn.

En las secciones de definiciones y reglas, cualquier texto sangrado o encerrado entre `%{' y `%}' se copia φntegramente a la salida (sin los %{}'s). Los %{}'s deben aparecer sin sangrar en lφneas ocupadas ·nicamente por estos.

En la secci≤n de reglas, cualquier texto o %{} sangrado que aparezca antes de la primera regla podrφa utilizarse para declarar variables que son locales a la rutina de anßlisis y (despuΘs de las declaraciones) al c≤digo que debe ejecutarse siempre que se entra a la rutina de anßlisis. Cualquier otro texto sangrado o %{} en la secci≤n de reglas sigue copißndose a la salida, pero su significado no estß bien definido y bien podrφa causar errores en tiempo de compilaci≤n (esta propiedad se presenta para conformidad con POSIX; para otras caracterφsticas similares) see section Incompatibilidades con lex y POSIX)

En la secci≤n de definiciones (pero no en la secci≤n de reglas), un comentario sin sangrφa (es decir, una lφnea comenzando con "/*") tambiΘn se copia literalmente a la salida hasta el pr≤ximo "*/".

Patrones

Los patrones en la entrada se escriben utilizando un conjunto extendido de expresiones regulares. Estas son:

`x'
empareja el caracter `x'
`.'
cualquier caracter (byte) excepto una lφnea nueva
`[xyz]'
una "clase de caracteres"; en este caso, el patr≤n empareja una `x', una `y', o una `z'
`[abj-oZ]'
una "clase de caracteres" con un rango; empareja una `a', una `b', cualquier letra desde la `j' hasta la `o', o una `Z'
`[^A-Z]'
una "clase de caracteres negada", es decir, cualquier caracter menos los que aparecen en la clase. En este caso, cualquier caracter EXCEPTO una letra may·scula.
`[^A-Z\n]'
cualquier caracter EXCEPTO una letra may·scula o una lφnea nueva
`r*'
cero o mßs r's, donde r es cualquier expresi≤n regular
`r+'
una o mßs r's
`r?'
cero o una r (es decir, "una r opcional")
`r{2,5}'
donde sea de dos a cinco r's
`r{2,}'
dos o mßs r's
`r{4}'
exactamente 4 r's
`{nombre}'
la expansi≤n de la definici≤n de "nombre" (ver mßs abajo)
`"[xyz]\"foo"'
la cadena literal: [xyz]"foo
`\x'
si x es una `a', `b', `f', `n', `r', `t', o `v', entonces la interpretaci≤n ANSI-C de \x. En otro caso, un literal `x' (usado para indicar operadores tales como `*')
`\0'
un caracter NUL (c≤digo ASCII 0)
`\123'
el caracter con valor octal 123
`\x2a'
el caracter con valor hexadecimal 2a
`(r)'
empareja una R; los parΘntesis se utilizan para anular la precedencia (ver mßs abajo)

`rs'
la expresi≤n regular r seguida por la expresi≤n regular s; se denomina "concatenaci≤n"

`r|s'
bien una r o una s

`r/s'
una r pero s≤lo si va seguida por una s. El texto emparejado por s se incluye cuando se determina si esta regla es el "emparejamiento mßs largo", pero se devuelve entonces a la entrada antes que se ejecute la acci≤n. Asφ que la acci≤n s≤lo ve el texto emparejado por r. Este tipo de patrones se llama "de contexto posterior". (Hay algunas combinaciones de r/s que flex no puede emparejar correctamente. See section Deficiencias / Errores, las notas a cerca del "contexto posterior peligroso".)
`^r'
una r, pero s≤lo al comienzo de una lφnea (es decir, justo al comienzo del anßlisis, o a la derecha despuΘs de que se haya analizado una lφnea nueva).
`r$'
una r, pero s≤lo al final de una lφnea (es decir, justo antes de una lφnea nueva). Equivalente a "r/\n". Fφjese que la noci≤n de flex de una "lφnea nueva" es exßctamente lo que el compilador de C utilizado para compilar flex interprete como `\n'; en particular, en algunos sistemas DOS debe filtrar los \r's de la entrada used mismo, o explφcitamente usar r/\r\n para "r$".
`<s>r'
una r, pero s≤lo en la condici≤n de arranque s (See section Condiciones de arranque, para una discusi≤n sobre las condiciones de arranque)
`<s1,s2,s3>r'
lo mismo, pero en cualquiera de las condiciones de arranque s1, s2, o s3
`<*>r'
una r en cualquier condici≤n de arranque, incluso una exclusiva.
`<<EOF>>'
un fin-de-fichero
`<s1,s2><<EOF>>'
un fin-de-fichero en una condici≤n de arranque s1s2

Fφjese que dentro de una clase de caracteres, todos los operadores de expresiones regulares pierden su significado especial excepto el caracter de escape (`\') y los operadores de clase de caracteres, `-', `]', y, al principio de la clase, `^'.

Las expresiones regulares en el listado anterior estßn agrupadas de acuerdo a la precedencia, desde la precedencia mßs alta en la cabeza a la mßs baja al final. Aquellas agrupadas conjuntamente tienen la misma precedencia. Por ejemplo,

foo|bar*

es lo mismo que

(foo)|(ba(r*))

ya que el operador `*' tiene mayor precedencia que la concatenaci≤n, y la concatenaci≤n mßs alta que el operador `|'. Este patr≤n por lo tanto empareja bien la cadena "foo" o la cadena "ba" seguida de cero o mßs r's. Para emparejar "foo" o, cero o mßs "bar"'s, use:

foo|(bar)*

y para emparejar cero o mßs "foo"'s o "bar"'s:

(foo|bar)*

Ademßs de caracteres y rangos de caracteres, las clases de caracteres pueden tambiΘn contener expresiones de clases de caracteres. Son expresiones encerradas entre los delimitadores `[:' y `:]' (que tambiΘn deben aparecer entre el `[' y el `]' de la clase de caracteres; ademßs pueden darse otros elementos dentro de la clase de caracteres). Las expresiones vßlidas son:

[:alnum:] [:alpha:] [:blank:]
[:cntrl:] [:digit:] [:graph:]
[:lower:] [:print:] [:punct:]
[:space:] [:upper:] [:xdigit:]

Todas estas expresiones designan un conjunto de caracteres equivalentes a la correspondiente funci≤n estßndar `isXXX' de C. Por ejemplo, `[:alnum:]' designa aquellos caracteres para los cuales `isalnum()' devuelve verdadero --es decir, cualquier caracter alfabΘtico o numΘrico. Algunos sistemas no ofrecen `isblank()', asφ que flex define `[:blank:]' como un espacio en blanco o un tabulador.

Por ejemplo, las siguientes clases de caracteres son todas equivalentes:

[[:alnum:]]
[[:alpha:][:digit:]]
[[:alpha:]0-9]
[a-zA-Z0-9]

Si su escßner ignora la distinci≤n entre may·sculas y min·sculas (la bandera `-i'), entonces `[:upper:]' y `[:lower:]' son equivalentes a `[:alpha:]'.

Algunas notas sobre los patrones:

C≤mo se empareja la entrada

Cuando el escßner generado estß funcionando, este analiza su entrada buscando cadenas que concuerden con cualquiera de sus patrones. Si encuentra mßs de un emparejamiento, toma el que empareje mßs texto (para reglas de contexto posterior, se incluye la longitud de la parte posterior, incluso si se devuelve a la entrada). Si encuentra dos o mßs emparejamientos de la misma longitud, se escoge la regla listada en primer lugar en el fichero de entrada de flex.

Una vez que se determina el emparejamiento, el texto correspondiente al emparejamiento (denominado el token) estß disponible en el puntero a caracter global yytext, y su longitud en la variable global entera yyleng. Entonces la acci≤n correspondiente al patr≤n emparejado se ejecuta (See section Acciones, para una descripci≤n mßs detallada de las acciones), y entonces la entrada restante se analiza para otro emparejamiento.

Si no se encuentra un emparejamiento, entonces se ejecuta la regla por defecto: el siguiente caracter en la entrada se considera reconocido y se copia a la salida estßndar. Asφ, la entrada vßlida mßs simple de flex es:

%%

que genera un escßner que simplemente copia su entrada (un caracter a la vez) a la salida.

Fφjese que yytext se puede definir de dos maneras diferentes: bien como un puntero a caracter o como un array de caracteres. Usted puede controlar la definici≤n que usa flex incluyendo una de las directivas especiales `%pointer' o `%array' en la primera secci≤n (definiciones) de su entrada de flex. Por defecto es `%pointer', a menos que use la opci≤n de compatibilidad `-l', en cuyo caso yytext serß un array.

La ventaja de usar `%pointer' es un anßlisis substancialmente mßs rßpido y la ausencia de desbordamiento del buffer cuando se emparejen tokens muy grandes (a menos que se agote la memoria dinßmica). La desventaja es que se encuentra restringido en c≤mo sus acciones pueden modificar yytext (see section Acciones), y las llamadas a la funci≤n `unput()' destruyen el contenido actual de yytext, que puede convertirse en un considerable quebradero de cabeza de portabilidad al cambiar entre diferentes versiones de lex.

La ventaja de `%array' es que entoces puede modificar yytext todo lo que usted quiera, las llamadas a `unput()' no destruyen yytext (ver mßs abajo). Ademßs, los programas de lex existentes a veces acceden a yytext externamente utilizando declaraciones de la forma:

extern char yytext[];

Esta definici≤n es err≤nea cuando se utiliza `%pointer', pero correcta para `%array'.

`%array' define a yytext como un array de YYLMAX caracteres, que por defecto es un valor bastante grande. Usted puede cambiar el tama±o sφmplemente definiendo con #define a YYLMAX con un valor diferente en la primera secci≤n de su entrada de flex. Como se mencion≤ antes, con `%pointer' yytext crece dinßmicamente para acomodar tokens grandes. Aunque esto signifique que con `%pointer' su escßner puede acomodar tokens muy grandes (tales como emparejar bloques enteros de comentarios), tenga presente que cada vez que el escßner deba cambiar el tama±o de yytext tambiΘn debe reiniciar el anßlisis del token entero desde el principio, asφ que emparejar tales tokens puede resultar lento. Ahora yytext no crece dinßmicamente si una llamada a `unput()' hace que se deba devolver demasiado texto; en su lugar, se produce un error en tiempo de ejecuci≤n.

TambiΘn tenga en cuenta que no puede usar `%array' en los analizadores generados como clases de C++ (see section Generando escßneres en C++).

Acciones

Cada patr≤n en una regla tiene una acci≤n asociada, que puede ser cualquier sentencia en C. El patr≤n finaliza en el primer caracter de espacio en blanco que no sea una secuencia de escape; lo que queda de la lφnea es su acci≤n. Si la acci≤n estß vacφa, entonces cuando el patr≤n se empareje el token de entrada simplemente se descarta. Por ejemplo, aquφ estß la especificaci≤n de un programa que borra todas las apariciones de "zap me" en su entrada:

%%
"zap me"

(Este copiarß el resto de caracteres de la entrada a la salida ya que serßn emparejados por la regla por defecto.)

Aquφ hay un programa que comprime varios espacios en blanco y tabuladores a un solo espacio en blanco, y desecha los espacios que se encuentren al final de una lφnea:

%%
[ \t]+        putchar( ' ' );
[ \t]+$       /* ignora este token */

Si la acci≤n contiene un `{', entonces la acci≤n abarca hasta que se encuentre el correspondiente `}', y la acci≤n podrφa entonces cruzar varias lφneas. flex es capaz de reconocer las cadenas y comentarios de C y no se dejarß enga±ar por las llaves que encuentre dentro de estos, pero aun asφ tambiΘn permite que las acciones comiencen con `%{' y considerarß que la acci≤n es todo el texto hasta el siguiente `%}' (sin tener en cuenta las llaves ordinarias dentro de la acci≤n).

Una acci≤n que consista s≤lamente de una barra vertical (`|') significa "lo mismo que la acci≤n para la siguiente regla." Vea mßs abajo para una ilustraci≤n.

Las acciones pueden incluir c≤digo C arbitrario, incuyendo sentencias return para devolver un valor desde cualquier rutina llamada `yylex()'. Cada vez que se llama a `yylex()' esta contin·a procesando tokens desde donde lo dej≤ la ·ltima vez hasta que o bien llegue al final del fichero o ejecute un return.

Las acciones tienen libertad para modificar yytext excepto para alargarla (a±adiendo caracteres al final--esto sobreescribirß mßs tarde caracteres en el flujo de entrada). Sin embargo esto no se aplica cuando se utiliza `%array' (see section C≤mo se empareja la entrada); en ese caso, yytext podrφa modificarse libremente de cualquier manera.

Las acciones tienen libertad para modificar yyleng excepto que estas no deberφan hacerlo si la acci≤n tambiΘn incluye el uso de `yymore()' (ver mßs abajo).

Hay un n·mero de directivas especiales que pueden incluirse dentro de una acci≤n:

Dos notas respecto al uso de `yymore()'. Primero, `yymore()' depende de que el valor de yyleng refleje correctamente el tama±o del token actual, asφ que no debe modificar yyleng si estß utilizando `yymore()'. Segundo, la presencia de `yymore()' en la acci≤n del escßner implica una peque±a penalizaci≤n de rendimiento en la velocidad de emparejamiento del escßner.

El escßner generado

La salida de flex es el fichero `lex.yy.c', que contiene la rutina de anßlisis `yylex()', un n·mero de tablas usadas por esta para emparejar tokens, y un n·mero de rutinas auxiliares y macros. Por defecto, `yylex()' se declara asφ

int yylex()
    {
    ... aquφ van varias definiciones y las acciones ...
    }

(Si su entorno acepta prototipos de funciones, entonces este serß "int yylex( void )"). Esta definici≤n podrφa modificarse definiendo la macro "YY_DECL". Por ejemplo, podrφa utilizar:

#define YY_DECL float lexscan( a, b ) float a, b;

para darle a la rutina de anßlisis el nombre lexscan, que devuelve un real, y toma dos reales como argumentos. Fφjese que si pone argumentos a la rutina de anßlisis usando una declaraci≤n de funci≤n no-prototipada/tipo-K&R, debe hacer terminar la definici≤n con un punto y coma (`;').

Siempre que se llame a `yylex()', este analiza tokens desde el fichero de entrada global yyin (que por defecto es igual a stdin). La funci≤n contin·a hasta que alcance el final del fichero (punto en el que devuelve el valor 0) o una de sus acciones ejecute una sentencia return.

Si el escßner alcanza un fin-de-fichero, entonces el comportamiento en las llamadas posteriores estß indefinido a menos que o bien yyin apunte a un nuevo fichero de entrada (en cuyo caso el anßlisis contin·a a partir de ese fichero), o se llame a `yyrestart()'. `yyrestart()' toma un argumento, un puntero `FILE *' (que puede ser nulo, si ha preparado a YY_INPUT para que analice una fuente distinta a yyin), e inicializa yyin para que escanee ese fichero. Esencialmente no hay diferencia entre la asignaci≤n a yyin de un nuevo fichero de entrada o el uso de `yyrestart()' para hacerlo; esto ·ltimo estß disponible por compatibilidad con versiones anteriores de flex, y porque puede utilizarse para conmutar ficheros de entrada en medio del anßlisis. TambiΘn se puede utilizar para desechar el buffer de entrada actual, invocßndola con un argumento igual a yyin; pero mejor es usar YY_FLUSH_BUFFER (see section Acciones). Fφjese que `yyrestart()' no reinicializa la condici≤n de arranque a INITIAL (see section Condiciones de arranque).

Si `yylex()' para el anßlisis debido a la ejecuci≤n de una sentencia return en una de las acciones, el analizador podrφa ser llamado de nuevo y este reanudarφa el anßlisis donde lo dej≤.

Por defecto (y por razones de eficiencia), el analizador usa lecturas por bloques en lugar de simples llamadas a `getc()' para leer caracteres desde yyin. La manera en la que toma su entrada se puede controlar definienfo la macro YY_INPUT. La secuencia de llamada para YY_INPUT es "YY_INPUT(buf,result,max_size)". Su acci≤n es poner hasta max_size caracteres en el array de caracteres buf y devolver en la variable entera result bien o el n·mero de caracteres leφdos o la constante YY_NULL (0 en sistemas Unix) para indicar EOF. Por defecto YY_INPUT lee desde la variable global puntero a fichero "yyin".

Una definici≤n de ejemplo para YY_INPUT (en la secci≤n de definiciones del fichero de entrada) es:

%{
#define YY_INPUT(buf,result,max_size) \
    { \
    int c = getchar(); \
    result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
    }
%}

Esta definici≤n cambiarß el procesamiento de la entrada para que suceda un caracter a la vez.

Cuando el analizador reciba una indicaci≤n de fin-de-fichero desde YY_INPUT, entonces esta comprueba la funci≤n `yywrap()'. Si `yywrap()' devuelve falso (cero), entonces se asume que la funci≤n ha ido mßs allß y ha preparado yyin para que apunte a otro fichero de entrada, y el anßlisis contin·a. Si este retorna verdadero (no-cero), entonces el analizador termina, devolviendo un 0 a su invocador. Fφjese que en cualquier caso, la condici≤n de arranque permanece sin cambios; esta no vuelve a ser INITIAL.

Si no proporciona su propia versi≤n de `yywrap()', entonces debe bien o usar `%option noyywrap' (en cuyo caso el analizador se comporta como si `yywrap()' devolviera un 1), o debe enlazar con `-lfl' para obtener la versi≤n por defecto de la rutina, que siempre devuelve un 1.

Hay disponibles tres rutinas para analizar desde buffers de memoria en lugar de desde ficheros: `yy_scan_string()', `yy_scan_bytes()', e `yy_scan_buffer()'. Las trataremos en la section M·ltiples buffers de entrada. El analizador escribe su salida con `ECHO' a la variable global yyout (por defecto, stdout), que el usuario podrφa redefinir asignßndole cualquier otro puntero a FILE.

Condiciones de arranque

flex dispone de un mecanismo para activar reglas condicionalmente. Cualquier regla cuyo patr≤n se prefije con "<sc>" ·nicamente estarß activa cuando el analizador se encuentre en la condici≤n de arranque llamada "sc". Por ejemplo,

<STRING>[^"]*        { /* se come el cuerpo de la cadena ... */
            ...
            }

estarß activa solamente cuando el analizador estΘ en la condici≤n de arranque "STRING", y

<INITIAL,STRING,QUOTE>\. { /* trata una secuencia de escape ... */
            ...
            }

estarß activa solamente cuando la condici≤n de arranque actual sea o bien "INITIAL", "STRING", o "QUOTE".

Las condiciones de arranque se declaran en la (primera) secci≤n de definiciones de la entrada usando lφneas sin sangrar comenzando con `%s'`%x' seguida por una lista de nombres. Lo primero declara condiciones de arranque inclusivas, lo ·ltimo condiciones de arranque exclusivas. Una condici≤n de arranque se activa utilizando la acci≤n BEGIN. Hasta que se ejecute la pr≤xima acci≤n BEGIN, las reglas con la condici≤n de arranque dada estarßn activas y las reglas con otras condiciones de arranque estarßn inactivas. Si la condici≤n de arranque es inclusiva, entonces las reglas sin condiciones de arranque tambiΘn estarßn activas. Si es exclusiva, entonces s≤lamente las reglas calificadas con la condici≤n de arranque estarßn activas. Un conjunto de reglas dependientes de la misma condici≤n de arranque exclusiva describe un analizador que es independiente de cualquiera de las otras reglas en la entrada de flex. Debido a esto, las condiciones de arranque exclusivas hacen fßcil la especificaci≤n de "mini-escßneres" que analizan porciones de la entrada que son sintßcticamente diferentes al resto (p.ej., comentarios).

Si la distinci≤n entre condiciones de arranque inclusivas o exclusivas es a·n un poco vaga, aquφ hay un ejemplo simple que ilustra la conexi≤n entre las dos. El conjunto de reglas:

%s ejemplo
%%

<ejemplo>foo   hacer_algo();

bar            algo_mas();

es equivalente a

%x ejemplo
%%

<ejemplo>foo   hacer_algo();

<INITIAL,ejemplo>bar    algo_mas();

Sin el calificador `<INITIAL,example>', el patr≤n `bar' en el segundo ejemplo no estarß activo (es decir, no puede emparejarse) cuando se encuentre en la condici≤n de arranque `example'. Si hemos usado `<example>' para calificar `bar', aunque, entonces este ·nicamente estarß activo en `example' y no en INITIAL, mientras que en el primer ejemplo estß activo en ambas, porque en el primer ejemplo la condici≤n de arranque `example' es una condici≤n de arranque inclusiva (`%s').

Fφjese tambiΘn que el especificador especial de la condici≤n de arranque `<*>' empareja todas las condiciones de arranque. Asφ, el ejemplo anterior tambiΘn pudo haberse escrito;

%x ejemplo
%%

<ejemplo>foo   hacer_algo();

<*>bar    algo_mas();

La regla por defecto (hacer un `ECHO' con cualquier caracter sin emparejar) permanece activa en las condiciones de arranque. Esta es equivalente a:

<*>.|\n     ECHO;

`BEGIN(0)' retorna al estado original donde solo las reglas sin condiciones de arranque estßn activas. Este estado tambiΘn puede referirse a la condici≤n de arranque "INITIAL", asφ que `BEGIN(INITIAL)' es equivalente a `BEGIN(0)'. (No se requieren los parΘntesis alrededor del nombre de la condici≤n de arranque pero se considera de buen estilo.)

Las acciones BEGIN pueden darse tambiΘn como c≤digo sangrado al comienzo de la secci≤n de reglas. Por ejemplo, lo que viene a continuaci≤n harß que el analizador entre en la condici≤n de arranque "ESPECIAL" siempre que se llame a `yylex()' y la variable global entra_en_especial sea verdadera:

        int entra_en_especial;

%x ESPECIAL
%%
        if ( entra_en_especial )
            BEGIN(ESPECIAL);

<ESPECIAL>blablabla
...mßs reglas a continuaci≤n...

Para ilustrar los usos de las condiciones de arranque, aquφ hay un analizador que ofrece dos interpretaciones diferentes para una cadena como "123.456". Por defecto este la tratarß como tres tokens, el entero "123", un punto (`.'), y el entero "456". Pero si la cadena viene precedida en la lφnea por la cadena "espera-reales" este la tratarß como un ·nico token, el n·mero en coma flotante 123.456:

%{
#include <math.h>
%}
%s espera

%%
espera-reales        BEGIN(espera);

<espera>[0-9]+"."[0-9]+      {
            printf( "encontr≤ un real, = %f\n",
                    atof( yytext ) );
            }
<espera>\n           {
            /* este es el final de la lφnea,
             * asφ que necesitamos otro
             * "espera-numero" antes de
             * que volvamos a reconocer mßs
             * n·meros
             */
            BEGIN(INITIAL);
            }

[0-9]+      {
            printf( "encontr≤ un entero, = %d\n",
                    atoi( yytext ) );
            }

"."         printf( "encontr≤ un punto\n" );

Aquφ estß un analizador que reconoce (y descarta) comentarios de C mientras mantiene una cuenta de la lφnea actual de entrada.

%x comentario
%%
        int num_linea = 1;

"/*"         BEGIN(comentario);

<comentario>[^*\n]*       /* come todo lo que no sea '*' */
<comentario>"*"+[^*/\n]*  /* come '*'s no seguidos por '/' */
<comentario>\n            ++num_linea;
<comentario>"*"+"/"       BEGIN(INITIAL);

Este analizador se complica un poco para emparejar tanto texto como le sea posible en cada regla. En general, cuando se intenta escribir un analizador de alta velocidad haga que cada regla empareje lo mßs que pueda, ya que esto es un buen logro.

Fφjese que los nombres de las condiciones de arranque son realmente valores enteros y pueden ser almacenados como tales. Asφ, lo anterior podrφa extenderse de la siguiente manera:

%x comentario foo
%%
        int num_linea = 1;
        int invocador_comentario;

"/*"         {
             invocador_comentario = INITIAL;
             BEGIN(comentario);
             }

...

<foo>"/*"    {
             invocador_comentario = foo;
             BEGIN(comentario);
             }

<comentario>[^*\n]*        /* se come cualquier cosa que no sea un '*' */
<comentario>"*"+[^*/\n]*   /* se come '*'s que no continuen con '/' */
<comentario>\n             ++num_linea;
<comentario>"*"+"/"        BEGIN(invocador_comentario);

Ademßs, puede acceder a la condici≤n de arranque actual usando la macro de valor entero YY_START. Por ejemplo, las asignaciones anteriores a invocador_comentario podrφan escribirse en su lugar como

invocador_comentario = YY_START;

Flex ofrece YYSTATE como un alias para YY_START (ya que es lo que usa lex de AT&T).

Fφjese que las condiciones de arranque no tienen su propio espacio de nombres; los %s's y %x's declaran nombres de la misma manera que con #define's.

Finalmente, aquφ hay un ejemplo de c≤mo emparejar cadenas entre comillas al estilo de C usando condiciones de arranque exclusivas, incluyendo secuencias de escape expandidas (pero sin incluir la comprobaci≤n de cadenas que son demasiado largas):

%x str

%%
        char string_buf[MAX_STR_CONST];
        char *string_buf_ptr;

\"      string_buf_ptr = string_buf; BEGIN(str);

<str>\"        { /* se vio la comilla que cierra - todo estß hecho */
        BEGIN(INITIAL);
        *string_buf_ptr = '\0';
        /* devuelve un tipo de token de cadena constante y
         * el valor para el analizador sintßctico
         */
        }

<str>\n        {
        /* error - cadena constante sin finalizar */
        /* genera un mensaje de error */
        }

<str>\\[0-7]{1,3} {
        /* secuencia de escape en octal */
        int resultado;

        (void) sscanf( yytext + 1, "%o", &resultado );

        if ( resultado > 0xff )
                /* error, constante fuera de rango */

        *string_buf_ptr++ = resultado;
        }

<str>\\[0-9]+ {
        /* genera un error - secuencia de escape err≤nea;
         * algo como '\48' o '\0777777'
         */
        }

<str>\\n  *string_buf_ptr++ = '\n';
<str>\\t  *string_buf_ptr++ = '\t';
<str>\\r  *string_buf_ptr++ = '\r';
<str>\\b  *string_buf_ptr++ = '\b';
<str>\\f  *string_buf_ptr++ = '\f';

<str>\\(.|\n)  *string_buf_ptr++ = yytext[1];

<str>[^\\\n\"]+        {
        char *yptr = yytext;

        while ( *yptr )
                *string_buf_ptr++ = *yptr++;

        }

A menudo, como en alguno de los ejemplos anteriores, uno acaba escribiendo un buen n·mero de reglas todas precedidas por la(s) misma(s) condici≤n(es) de arranque. Flex hace esto un poco mßs fßcil y claro introduciendo la noci≤n de ßmbito de la condici≤n de arranque. Un ßmbito de condici≤n de arranque comienza con:

<SCs>{

Donde `SCs' es una lista de una o mßs condiciones de arranque. Dentro del ßmbito de la condici≤n de arranque, cada regla automßticamente tiene el prefijo `<SCs>' aplicado a esta, hasta un `}' que corresponda con el `{' inicial. Asφ, por ejemplo,

<ESC>{
    "\\n"   return '\n';
    "\\r"   return '\r';
    "\\f"   return '\f';
    "\\0"   return '\0';
}

es equivalente a:

<ESC>"\\n"  return '\n';
<ESC>"\\r"  return '\r';
<ESC>"\\f"  return '\f';
<ESC>"\\0"  return '\0';

Los ßmbitos de las condiciones de arranque pueden anidarse.

Estßn disponibles tres rutinas para manipular pilas de condiciones de arranque:

`void yy_push_state(int new_state)'
empuja la condici≤n de arranque actual al tope de la pila de las condiciones de arranque y cambia a new_state como si hubiera utilizado `BEGIN new_state' (recuerde que los nombres de las condiciones de arranque tambiΘn son enteros).
`void yy_pop_state()'
extrae el tope de la pila y cambia a este mediante un BEGIN.
`int yy_top_state()'
devuelve el tope de la pila sin alterar el contenido de la pila.

La pila de las condiciones de arranque crece dinßmicamente y por ello no tiene asociada ninguna limitaci≤n de tama±o. Si la memoria se agota, se aborta la ejecuci≤n del programa.

Para usar pilas de condiciones de arranque, su analizador debe incluir una directiva `%option stack' (see section Opciones).

M·ltiples buffers de entrada

Algunos analizadores (tales como aquellos que aceptan ficheros "incluidos") requieren la lectura de varios flujos de entrada. Ya que los analizadores de flex hacen mucho uso de buffers, uno no puede controlar de d≤nde serß leφda la siguiente entrada escribiendo sφmplemente un YY_INPUT que sea sensible al contexto del anßlisis. A YY_INPUT s≤lo se le llama cuando el analizador alcanza el final de su buffer, que podrφa ser bastante tiempo despuΘs de haber analizado una sentencia como un "include" que requiere el cambio de la fuente de entrada.

Para solventar este tipo de problemas, flex provee un mecanismo para crear y conmutar entre varios buffers de entrada. Un buffer de entrada se crea usando:

YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )

que toma un puntero a FILE y un tama±o "size" y crea un buffer asociado con el fichero dado y lo suficientemente grande para mantener size caracteres (cuando dude, use YY_BUF_SIZE para el tama±o). Este devuelve un handle YY_BUFFER_STATE, que podrφa pasarse a otras rutinas (ver mßs abajo). El tipo de YY_BUFFER_STATE es un puntero a una estructura opaca struct yy_buffer_state, de manera que podrφa inicializar de forma segura variables YY_BUFFER_STATE a `((YY_BUFFER_STATE) 0)' si lo desea, y tambiΘn hacer referencia a la estructura opaca para declarar correctamente buffers de entrada en otros ficheros fuente ademßs de los de su analizador. Fφjese que el puntero a FILE en la llamada a yy_create_buffer se usa solamente como el valor de yyin visto por YY_INPUT; si usted redefine YY_INPUT de manera que no use mßs a yyin, entonces puede pasar de forma segura un puntero FILE nulo a yy_create_buffer. Se selecciona un buffer en particular a analizar utilizando:

void yy_switch_to_buffer( YY_BUFFER_STATE nuevo_buffer )

conmuta el buffer de entrada del analizador de manera que los tokens posteriores provienen de nuevo_buffer. Fφjese que `yy_switch_to_buffer()' podrφa usarlo yywrap() para arreglar las cosas para un anßlisis continuo, en lugar de abrir un nuevo fichero y que yyin apunte a este. Fφjese tambiΘn que cambiar las fuentes de entrada ya sea por medio de `yy_switch_to_buffer()' o de `yywrap()' no cambia la condici≤n de arranque.

void yy_delete_buffer( YY_BUFFER_STATE buffer )

se usa para recuperar el almacenamiento asociado a un buffer. (El buffer puede ser nulo, en cuyo caso la rutina no hace nada.) Puede tambiΘn limpiar el contenido actual de un buffer usando:

void yy_flush_buffer( YY_BUFFER_STATE buffer )

Esta funci≤n descarta el contenido del buffer, de manera que la pr≤xima vez que el analizador intente emparejar un token desde el buffer, este primero rellenarß el buffer utilizando YY_INPUT.

`yy_new_buffer()' es un alias de `yy_create_buffer()', que se ofrece por compatibilidad con el uso en C++ de new y delete para crear y destruir objetos dinßmicos.

Finalmente, la macro YY_CURRENT_BUFFER retorna un handle YY_BUFFER_STATE al buffer actual.

Aquφ hay un ejemplo del uso de estas propiedades para escribir un analizador que expande ficheros incluidos (la propiedad `<<EOF>>' se comenta en el section Reglas de fin-de-fichero):

/* el estado "incl" se utiliza para obtener el nombre
 * del fichero a incluir.
 */
%x incl

%{
#define MAX_INCLUDE_DEPTH 10
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr = 0;
%}

%%
include             BEGIN(incl);

[a-z]+              ECHO;
[^a-z\n]*\n?        ECHO;

<incl>[ \t]*      /* se come los espacios en blanco */
<incl>[^ \t\n]+   { /* obtiene el nombre de fichero a incluir */
        if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
            {
            fprintf( stderr, "Demasiados include anidados" );
            exit( 1 );
            }

        include_stack[include_stack_ptr++] =
            YY_CURRENT_BUFFER;

        yyin = fopen( yytext, "r" );

        if ( ! yyin )
            error( ... );

        yy_switch_to_buffer(
            yy_create_buffer( yyin, YY_BUF_SIZE ) );

        BEGIN(INITIAL);
        }

<<EOF>> {
        if ( --include_stack_ptr < 0 )
            {
            yyterminate();
            }

        else
            {
            yy_delete_buffer( YY_CURRENT_BUFFER );
            yy_switch_to_buffer(
                 include_stack[include_stack_ptr] );
            }
        }

Se dispone de tres rutinas para preparar buffers de entrada para el anßlisis de cadenas en memoria en lugar de archivos. Todas estas crean un nuevo buffer de entrada para analizar la cadena, y devuelven el correspondiente handle YY_BUFFER_STATE (que usted deberφa borrar con `yy_delete_buffer()' cuando termine con Θl). Estas tambiΘn conmutan el nuevo buffer usando `yy_switch_to_buffer()', de manera que la pr≤xima llamada a `yylex()' comenzarß analizando la cadena.

`yy_scan_string(const char *str)'
analiza una cadena terminada en nulo.
`yy_scan_bytes(const char *bytes, int len)'
analiza len bytes (incluyendo posibles NUL's) comenzando desde el punto bytes.

Fφjese que ambas de estas funciones crean y analizan una copia de la cadena o bytes. (Esto podrφa ser deseable, ya que `yylex()' modifica el contenido del buffer que estß analizado.) Usted puede evitar la copia utilizando:

`yy_scan_buffer(char *base, yy_size_t size)'
que analiza in situ el buffer comenzando en base, que consiste de size bytes, donde los dos ·ltimos bytes deben ser YY_END_OF_BUFFER_CHAR (ASCII NUL). Estos dos ·ltimos bytes no se analizan; asφ, el anßlisis consta de `base[0]' hasta `base[size-2]', inclusive. Si se equivoca al disponer base de esta manera (es decir, olvidar los dos YY_END_OF_BUFFER_CHAR bytes finales), entonces `yy_scan_buffer()' devuelve un puntero nulo en lugar de crear un nuevo buffer de entrada. El tipo yy_size_t es un tipo entero con el que puede hacer una conversi≤n a una expresi≤n entera para reflejar el tama±o del buffer.

Reglas de fin-de-fichero

La regla especial "<<EOF>>" indica las acciones que deben tomarse cuando se encuentre un fin-de-fichero e yywrap() retorne un valor distinto de cero (es decir, indica que no quedan ficheros por procesar). La acci≤n debe finalizar haciendo una de estas cuatro cosas:

Las reglas <<EOF>> no deberφan usarse con otros patrones; estas deberφan calificarse con una lista de condiciones de arranque. Si se da una regla <<EOF>> sin calificar, esta se aplica a todas las condiciones de arranque que no tengan ya acciones <<EOF>>. Para especificar una regla <<EOF>> solamente para la condici≤n de arranque inicial, use

<INITIAL><<EOF>>

Estas reglas son ·tiles para atrapar cosas tales como comentarios sin final. Un ejemplo:

%x comilla
%%

...otras reglas que tengan que ver con comillas...

<comilla><<EOF>>   {
         error( "comilla sin cerrar" );
         yyterminate();
         }
<<EOF>>  {
         if ( *++filelist )
             yyin = fopen( *filelist, "r" );
         else
            yyterminate();
         }

Macros miscelßneas

La macro YY_USER_ACTION puede definirse para indicar una acci≤n que siempre se ejecuta antes de la acci≤n de la regla emparejada. Por ejemplo, podrφa declararse con #define para que llame a una rutina que convierta yytext a min·sculas. Cuando se invoca a YY_USER_ACTION, la variable yy_act da el n·mero de la regla emparejada (las reglas estßn numeradas comenzando en 1). Suponga que quiere medir la frecuencia con la que sus reglas son emparejadas. Lo que viene a continuaci≤n podrφa hacer este truco:

#define YY_USER_ACTION ++ctr[yy_act]

donde ctr en un vector que mantiene la cuenta para las diferentes reglas. Fφjese que la macro YY_NUM_RULES da el n·mero total de reglas (incluyendo la regla por defecto, incluso si usted usa `-s'), asφ que una declaraci≤n correcta para ctr es:

int ctr[YY_NUM_RULES];

La macro YY_USER_INIT podrφa definirse para indicar una acci≤n que siempre se ejecuta antes del primer anßlisis (y antes de que se haga la inicializaci≤n interna del analizador). Por ejemplo, este podrφa usarse para llamar a una rutina que lea una tabla de datos o abrir un fichero de registro.

La macro `yy_set_interactive(is_interactive)' se puede usar para controlar si el buffer actual se considera interactivo. Un buffer interactivo se procesa mßs lentamente, pero debe usarse cuando la fuente de entrada del analizador es realmente interactiva para evitar problemas debidos a la espera para el llenado de los buffers (ver el comentario de la bandera `-I' en la section Opciones). Un valor distinto de cero en la invocaci≤n de la macro marcarß el buffer como interactivo, un valor de cero como no-interactivo. Fφjese que el uso de esta macro no tiene en cuenta `%option always-interactive' o `%option never-interactive' (see section Opciones). `yy_set_interactive()' debe invocarse antes del comienzo del anßlisis del buffer que es considerado (o no) interactivo.

La macro `yy_set_bol(at_bol)' puede usarse para controlar si el contexto del buffer de anßlisis actual para el pr≤ximo emparejamiento de token se hace como si se encontrara al principio de una lφnea. Un argumento de la macro distinto de cero hace activas a las reglas sujetas a `^', mientras que un argumento igual a cero hacer inactivas a las reglas con `^'.

La macro `YY_AT_BOL()' devuelve verdadero si el pr≤ximo token analizado a partir del buffer actual tendrß activas las reglas `^', de otra manera falso.

En el analizador generado, las acciones estßn recogidas en una gran sentencia switch y separadas usando YY_BREAK, que puede ser redefinida. Por defecto, este es sφmplemente un "break", para separar la acci≤n de cada regla de las reglas que le siguen. Redefiniendo YY_BREAK permite, por ejemplo, a los usuarios de C++ que #define YY_BREAK no haga nada (ímientras tengan cuidado para que cada regla finalice con un "break" o un "return"!) para evitar que sufran los avisos de sentencias inalcanzables cuando debido a que la acci≤n de la regla finaliza con un "return", el YY_BREAK es inaccesible.

Valores disponibles al usuario

Esta secci≤n resume los diferentes valores disponibles al usuario en las acciones de la regla.

Interfaz con YACC

Uno de los usos principales de flex es como compa±ero del generador de analizadores sintßcticos yacc. Los analizadores de yacc esperan invocar a una rutina llamada `yylex()' para encontrar el pr≤ximo token de entrada. La rutina se supone que devuelve el tipo del pr≤ximo token ademßs de poner cualquier valor asociado en la variable global yylval. Para usar flex con yacc, uno especifica la opci≤n `-d' de yacc para intruirle a que genere el fichero `y.tab.h' que contiene las definiciones de todos los `%tokens' que aparecen en la entrada de yacc. Entonces este archivo se incluye en el analizador de flex. Por ejemplo, si uno de los tokens es "TOK_NUMERO", parte del analizador podrφa parecerse a:

%{
#include "y.tab.h"
%}

%%

[0-9]+        yylval = atoi( yytext ); return TOK_NUMERO;

Invocando a Flex

Sinopsis

flex [-bcdfhilnpstvwBFILTV78+? -C[aefFmr] -osalida -Pprefijo -Sesqueleto]
[--help --version] [nombrefichero ...]

Opciones

flex tiene las siguientes opciones:

`-b'
Genera informaci≤n de retroceso en `lex.backup'. Esta es una lista de estados del analizador que requieren retroceso y los caracteres de entrada con los que la hace. A±adiendo reglas uno puede eliminar estados de retroceso. Si todos los estados de retroceso se eliminan y se usa `-Cf'`-CF', el analizador generado funcionarß mßs rßpido (ver la bandera `-p'). ┌nicamente los usuarios que desean exprimir hasta el ·ltimo ciclo de sus analizadores necesitan preocuparse de esta opci≤n. (see section Consideraciones de rendimiento)
`-c'
es una opci≤n que no hace nada, incluφda para cumplir con POSIX.
`-d'
hace que el analizador generado se ejecute en modo de depuraci≤n. Siempre que se reconoce un patr≤n y la variable global `yy_flex_debug' no es cero (que por defecto no lo es), el analizador escribirß en stderr una lφnea de la forma:
--accepting rule at line 53 ("el texto emparejado")
El n·mero de lφnea hace referencia al lugar de la regla en el fichero que define al analizador (es decir, el fichero que se le introdujo a flex). Los mensajes tambiΘn se generan cuando el analizador retrocede, acepta la regla por defecto, alcanza el final de su buffer de entrada (o encuentra un NUL; en este punto, los dos parecen lo mismo en lo que le concierne al analizador), o alcance el fin-de-fichero.
`-f'
especifica un analizador rßpido. No se realiza una compresi≤n de tablas y se evita el uso de stdio. El resultado es grande pero rßpido. Esta opci≤n es equivalente a `-Cfr' (ver mßs abajo).
`-h'
genera un sumario de "ayuda" de las opciones de flex por stdout y entonces finaliza. `-?' y `--help' son sin≤nimos de `-h'.
`-i'
indica a flex que genere un analizador case-insensitive. Se ignorarß si las letras en los patrones de entrada de flex son en may·sculas o en min·sculas, y los tokens en la entrada serßn emparejados sin tenerlo en cuenta. El texto emparejado dado en yytext tendrß las may·sculas y min·sculas preservadas (es decir, no se convertirßn).
`-l'
activa el modo de mßxima compatibilidad con la implementaci≤n original de lex de AT&T. Fφjese que esto no significa una compatibilidad completa. El uso de esta opci≤n cuesta una cantidad considerable de rendimiento, y no puede usarse con las opciones `-+', `-f', `-F', `-Cf', ≤ `-CF'. Para los detalles a cerca de la compatibilidad que se ofrece, vea la section Incompatibilidades con lex y POSIX. Esta opci≤n tambiΘn hace que se defina el nombre YY_FLEX_LEX_COMPAT en el analizador generado.
`-n'
es otra opci≤n que no hace nada, incluφda para cumplir con POSIX.
`-p'
genera un informe de rendimiento en stderr. El informe consta de comentarios que tratan de las propiedades del fichero de entrada de flex que provocarßn pΘrdidas serias de rendimiento en el analizador resultante. Si indica esta bandera dos veces, tambiΘn obtendrß comentarios que tratan de las propiedades que producen pΘrdidas menores de rendimiento. Fφjese que el uso de REJECT, `%option yylineno', y el contexto posterior variable (see section Deficiencias / Errores) supone una penalizaci≤n substancial del rendimiento; el uso de `yymore()', el operador `^', y la bandera `-I' supone penalizaciones del rendimiento menores.
`-s'
hace que la regla por defecto (que la entrada sin emparejar del analizador se repita por stdout) se suprima. Si el analizador encuentra entrada que no es reconocida por ninguna de sus reglas, este aborta con un error. Esta opci≤n es ·til para encontrar agujeros en el conjunto de reglas del analizador.
`-t'
indica a flex que escriba el analizador que genera a la salida estßndar en lugar de en `lex.yy.c'.
`-v'
especifica que flex deberφa escribir en stderr un sumario de estadφsticas respecto al analizador que genera. La mayorφa de las estadφsticas no tienen significado para el usuario casual de flex, pero la primera lφnea identifica la versi≤n de flex (la misma que se informa con `-V'), y la pr≤xima lφnea las banderas utilizadas cuando se genera el analizador, incluyendo aquellas que se encuentran activadas por defecto.
`-w'
suprime los mensajes de aviso.
`-B'
dice a flex que genere un analizador batch, que es lo opuesto al analizador interactivo generador por `-I' (ver mßs abajo). En general, use `-B' cuando estΘ seguro de que su analizador nunca se usarß de forma interactiva, y quiere con esto exprimir un poco mßs el rendimiento. Si por el contrario su objetivo es exprimirlo mucho mßs, deberφa estar utilizando la opci≤n `-Cf'`-CF' (comentadas mßs abajo), que activa `-B' automßticamente de todas maneras.
`-F'
especifica que se debe utilizar la representaci≤n de la tabla rßpida (y elimina referencias a stdio). Esta representaci≤n es aproximadamente tan rßpida como la representaci≤n completa de la tabla `(-f)', y para algunos conjuntos de patrones serß considerablemente mßs peque±a (y para otros, mayor). En general, si el conjunto de patrones contiene "palabras clave" y una regla "identificador" atrßpalo-todo, como la del conjunto:
"case"    return TOK_CASE;
"switch"  return TOK_SWITCH;
...
"default" return TOK_DEFAULT;
[a-z]+    return TOK_ID;
entonces serß mejor que utilice la representaci≤n de la tabla completa. Si s≤lo estß presente la regla "identificador" y utiliza una tabla hash o algo parecido para detectar palabras clave, mejor utilice `-F'. Esta opci≤n es equivalente a `-CFr' (ver mßs abajo). Esta opci≤n no puede utilizarse con `-+'.
`-I'
ordena a flex que genere un analizador interactivo. Un analizador interactivo es uno que solo mira hacia delante para decidir que token ha sido reconocido ·nicamente si debe hacerlo. Resulta que mirando siempre un caracter extra hacia delante, incluso si el analizador ya ha visto suficiente texto para eliminar la ambigⁿedad del token actual, se es un poco mßs rßpido que mirando solamente cuando es necesario. Pero los analizadores que siempre miran hacia delante producen un comportamiento interactivo malφsimo; por ejemplo, cuando un usuario teclea una lφnea nueva, esta no se reconoce como un token de lφnea nueva hasta que introduzca otro token, que a menudo significa introducir otra lφnea completa. Los analizadores de flex por defecto son interactivos a menos que use la opci≤n `-Cf'`-CF' de compresi≤n de tablas (ver mßs abajo). Esto es debido a que si estß buscando un rendimiento alto tendrφa que estar utilizando una de estas opciones, asφ que si no lo ha hecho flex asume que prefiere cambiar un poco de rendimiento en tiempo de ejecuci≤n en beneficio de un comportamiento iteractivo intuitivo. Fφjese tambiΘn que no puede utilizar `-I' conjuntamente con `-Cf'`-CF'. Asφ, esta opci≤n no se necesita realmente; estß activa por defecto para todos esos casos en los que se permite. Usted puede forzar al analizador que no sea interactivo usando `-B' (ver mßs arriba).
`-L'
ordena a flex que no genere directivas `#line'. Sin esta opci≤n, flex acribilla al analizador generado con directivas `#line' para que los mensajes de error en las acciones estΘn localizadas correctamente respecto al fichero original de flex (si los errores son debidos al c≤digo en el fichero de entrada), o a `lex.yy.c' (si los errores son fallos de flex --deberφa informar de este tipo de errores a la direcci≤n de correo dada mßs abajo).
`-T'
hace que flex se ejecute en modo de traza. Este generarß un mont≤n de mensajes en stderr relativos a la forma de la entrada y el aut≤mata finito no-determinista o determinista resultante. Esta opci≤n generalmente es para usarla en el mantenimiento de flex.
`-V'
imprime el n·mero de la versi≤n en stdout y sale. `--version' es un sin≤nimo de `-V'.
`-7'
ordena a flex que genere un analizador de 7-bits, es decir, uno que s≤lo puede reconocer caracteres de 7-bits en su entrada. La ventaja de usar `-7' es que las tablas del analizador pueden ser hasta la mitad del tama±o de aquellas generadas usando la opci≤n `-8' (ver mßs abajo). La desventaja es que tales analizadores a menudo se cuelgan o revientan si su entrada contiene caracteres de 8-bits. Fφjese, sin embargo, que a menos que genere su analizador utilizando las opciones de compresi≤n de tablas `-Cf'`-CF', el uso de `-7' ahorrarß solamente una peque±a cantidad de espacio en la tabla, y harß su analizador considerablemente menos portable. El comportamiento por defecto de flex es generar un analizador de 8-bits a menos que use `-Cf'`-CF', en cuyo caso flex por defecto genera analizadores de 7-bits a menos que su sistema siempre estΘ configurado para generar analizadores de 8-bits (a menudo este serß el caso de los sistemas fuera de EEUU). Puede decir si flex gener≤ un analizador de 7 u 8 bits inspeccionando el sumario de banderas en la salida de `-v' como se describi≤ anteriormente. Fφjese que si usa `-Cfe'`-CFe' (esas opciones de compresi≤n de tablas, pero tambiΘn el uso de clases de equivalencia como se comentarß mßs abajo), flex genera a·n por defecto un analizador de 8-bits, ya que normalmente con estas opciones de compresi≤n las tablas de 8-bits completas no son mucho mßs caras que las tablas de 7-bits.
`-8'
ordena a flex que genere un analizador de 8-bits, es decir, uno que puede reconocer caracteres de 8-bits. Esta bandera s≤lo es necesaria para analizadores generados usando `-Cf'`-CF', ya que de otra manera flex por defecto genera un analizador de 8-bits de todas formas. Vea el comentario sobre `-7' mßs arriba a cerca del comportamiento por defecto de flex y la discusi≤n entre los analizadores de 7-bits y 8-bits.
`-+'
especifica que quiere que flex genere un analizador como una clase de C++. Vea la section Generando escßneres en C++, para los detalles.
`-C[aefFmr]'
controla el grado de compresi≤n de la tabla y, mßs generalmente, el compromiso entre analizadores peque±os y analizadores rßpidos.
`-Ca'
("alinea") ordena a flex que negocie tablas mßs grandes en el analizador generado para un comportamiento mßs rßpido porque los elementos de las tablas estßn mejor alineados para el acceso a memoria y computaci≤n. En algunas arquitecturas RISC, la b·squeda y manipulaci≤n de palabras largas es mßs eficiente que con unidades mßs peque±as tales como palabras cortas. Esta opci≤n puede doblar el tama±o de las tablas usadas en su analizador.
`-Ce'
ordena a flex que construya clases de equivalencia, es decir, conjunto de caracteres que tienen identicas propiedades lΘxicas (por ejemplo, si la ·nica aparici≤n de dφgitos en la entrada de flex es en la clase de caracteres "[0-9]" entonces los dφgitos `0', `1', ..., `9' se pondrßn todos en la misma clase de equivalencia). Las clases de equivalencia normalmente ofrecen notables reducciones en los tama±os de los ficheros finales de tabla/objeto (tφpicamente un factor de 2-5) y son juiciosamente bastante baratos en cuanto al rendimiento (una localizaci≤n en un vector por caracter analizado). `-Cf' especifica que se deben generar las tablas del analizador completas ---flex no deberφa comprimir las tablas tomando ventaja de las funciones de transici≤n similares para diferentes estados. `-CF' especifica que deberφa usarse la representaci≤n del analizador rßpido alternativo (descrito anteriormente en la bandera `-F' ) Esta opci≤n no puede usarse con `-+'.
`-Cm'
ordena a flex que construya clases de meta-equivalencias, que son conjuntos de clases de equivalencia (o caracteres, si las clases de equivalencia no se estßn usando) que comunmente se usan de forma conjunta. Las clases de meta-equivalencias son a menudo un gran ahorro cuando se usan tablas comprimidas, pero tienen un impacto moderado en el rendimiento (uno o dos tests "if" y una localizaci≤n en un array por caracter analizado). `-Cr' hace que el analizador generado elimine el uso de la librerφa de E/S estßndar para la entrada. En lugar de llamar a `fread()' o a `getc()', el analizador utilizarß la llamada al sistema `read()', produciendo una ganancia en el rendimiento que varφa de sistema en sistema, pero en general probablemente es insignificante a menos que tambiΘn estΘ usando `-Cf'`-CF'. El uso de `-Cr' puede producir un comportamiento extra±o si, por ejemplo, lee de yyin usando stdio antes de llamar al analizador (porque el analizador perderß cualquier texto que sus lecturas anteriores dejaron en el buffer de entrada de stdio). `-Cr' no tiene efecto si usted define YY_INPUT (see section El escßner generado). Con solamente `-C' se especifica que las tablas del analizador deberφan comprimirse pero no deberφa utilizarse ni las clases de equivalencia ni las clases de meta-equivalencias. Las opciones `-Cf'`-CF' y `-Cm' no tienen sentido juntas --no hay oportunidad para las clases de meta-equivalencias si la tabla no estß siendo comprimida. De otra forma las opciones podrφan mezclarse lφbremente, y son acumulativas. La configuraci≤n por defecto es `-Cem', que especifica que flex deberφa generar clases de equivalencia y clases de meta-equivalencias. Esta configuraci≤n provee el mayor grado de compresi≤n. Puede llegarse a un compromiso entre analizadores de ejecuci≤n mßs rßpida con el coste de tablas mayores siendo generalmente verdadero lo siguiente:
lo mßs lento y peque±o
      -Cem
      -Cm
      -Ce
      -C
      -C{f,F}e
      -C{f,F}
      -C{f,F}a
lo mßs rßpido y grande
Fφjese que los analizadores con tablas mßs peque±as normalmente se generan y compilan de la forma mßs rßpida posible, asφ que durante el desarrollo usted normalmente querrß usar como viene por defecto, compresi≤n mßxima. `-Cfe' a menudo es un buen compromiso entre velocidad y tama±o para la producci≤n de analizadores.
`-osalida'
ordena a flex que escriba el analizador al fichero `salida' en lugar de a `lex.yy.c'. Si combina `-o' con la opci≤n `-t', entonces el analizador se escribe en stdout pero sus directivas `#line' (vea la opci≤n `-L' mßs arriba) hacen referencia al fichero `salida'.
`-Pprefijo'
cambia el prefijo `yy' usado por defecto por flex para todas las variables visibles globalmente y nombres de funciones para que sea prefijo. Por ejemplo, `-Pfoo' cambia el nombre de yytext a `footext'. Este tambiΘn cambia el nombre por defecto del fichero de salida de `lex.yy.c' a `lex.foo.c'. Aquφ estßn todos los nombres afectados:
yy_create_buffer
yy_delete_buffer
yy_flex_debug
yy_init_buffer
yy_flush_buffer
yy_load_buffer_state
yy_switch_to_buffer
yyin
yyleng
yylex
yylineno
yyout
yyrestart
yytext
yywrap
(Si usted estß utilizando un analizador en C++, entonces ·nicamente yywrap y yyFlexLexer se ven afectados.) Dentro de su analizador, puede a·n hacer referencia a las variables globales y funciones usando cualquier versi≤n de su nombre; pero externamente, estas tienen el nombre modificado. Esta opci≤n le deja enlazar fßcilmente m·ltiples programas flex conjuntamente en el mismo ejecutable. Fφjese, sin embargo, que usando esta opci≤n tambiΘn se renombra `yywrap()', de manera que ahora debe o bien proveer su propia versi≤n de la rutina (con el nombre apropiado) para su analizador, o usar `%option noyywrap', ya que enlazar con `-lfl' no podrß proveerle una por defecto.
`-Sfichero_esqueleto'
ignora el fichero de esqueleteo por defecto con el que flex construye sus analizadores. Usted probablemente nunca necesitarß utilizar esta opci≤n a menos que este haciendo mantenimiento o un desarrollo de flex.

flex tambiΘn ofrece un mecanismo para controlar las opciones dentro de la propia especificaci≤n del analizador, en vez de a partir de la lφnea de comando. Esto se hace incluyendo las directivas `%option' en la primera secci≤n de la especificaci≤n del analizador. Usted puede especificar varias opciones con una sola directiva `%option', y varias directivas en la primera secci≤n de su fichero de entrada de flex.

La mayorφa de las opciones vienen dadas simplemente como nombres, opcionalmente precedidos por la palabra "no" (sin intervenir un espacio) para negar su significado. Las banderas de flex o su negaci≤n son equivalentes a un n·mero:

7bit            opci≤n -7
8bit            opci≤n -8
align           opci≤n -Ca
backup          opci≤n -b
batch           opci≤n -B
c++             opci≤n -+

caseful o
case-sensitive  opuesto de -i (por defecto)

case-insensitive o
caseless        opci≤n -i

debug           opci≤n -d
default         opuesto de la opci≤n -s
ecs             opci≤n -Ce
fast            opci≤n -F
full            opci≤n -f
interactive     opci≤n -I
lex-compat      opci≤n -l
meta-ecs        opci≤n -Cm
perf-report     opci≤n -p
read            opci≤n -Cr
stdout          opci≤n -t
verbose         opci≤n -v
warn            opuesto de la opci≤n -w
                (use "%option nowarn" para -w)

array           equivalente a "%array"
pointer         equivalente a "%pointer" (por defecto)

Algunas directivas `%option' ofrecen propiedades que de otra manera no estßn disponibles:

`always-interactive'
ordena a flex que genere un analizador que siempre considere su entrada como "interactiva". Normalmente, sobre cada fichero de entrada nuevo el analizador llama a `isatty()' como intento para determinar si la entrada del analizador es interactiva y por lo tanto deberφa leer un caracter a la vez. Cuando esta opci≤n se utilice, sin embargo, entonces no se hace tal llamada.
`main'
ordena a flex que facilite un programa `main()' por defecto para el analizador, que simplemente llame a `yylex()'. Esta opci≤n implica noyywrap (ver mßs abajo).
`never-interactive'
ordena a flex que genere un analizador que nunca considere su entrada como "interactiva" (de nuevo, no se hace ninguna llamada a `isatty()'). Esta es la opuesta a `always-interactive'.
`stack'
activa el uso de pilas de condiciones de arranque (see section Condiciones de arranque).
`stdinit'
si se establece (es decir, `%option stdinit') inicializa yyin e yyout a stdin y stdout, en lugar del que viene por defecto que es nil. Algunos pogramas de lex existentes dependen de este comportamiento, incluso si no sigue el ANSI C, que no requiere que stdin y stdout sean constantes en tiempo de compilaci≤n.
`yylineno'
ordena a flex a generar un analizador que mantenga el n·mero de la lφnea actual leφda desde su entrada en la variable global yylineno. Esta opci≤n viene implφcita con `%option lex-compat'.
`yywrap'
si no se establece (es decir, `%option noyywrap'), hace que el analizador no llame a `yywrap()' hasta el fin-de-fichero, pero simplemente asume que no hay mßs ficheros que analizar (hasta que el usuario haga apuntar yyin a un nuevo fichero y llame a `yylex()' otra vez).

flex analiza las acciones de sus reglas para determinar si utiliza las propiedades REJECT o `yymore()'. Las opciones reject e yymore estßn disponibles para ignorar sus decisiones siempre que use las opciones, o bien estableciendolas (p.ej., `%option reject') para indicar que la propiedad se utiliza realmente, o desactivßndolas para indicar que no es utilizada (p.ej., `%option noyymore').

Tres opciones toman valores delimitados por cadenas, separadas por `=':

%option outfile="ABC"

es equivalente a `-oABC', y

%option prefix="XYZ"

es equivalente a `-PXYZ'. Finalmente,

%option yyclass="foo"

s≤lo se aplica cuando se genera un analizador en C++ (opci≤n `-+'). Este informa a flex que ha derivado a `foo' como una subclase de yyFlexLexer, asφ que flex pondrß sus acciones en la funci≤n miembro `foo::yylex()' en lugar de `yyFlexLexer::yylex()'. Este tambiΘn genera una funci≤n miembro `yyFlexLexer::yylex()' que emite un error en tiempo de ejecuci≤n (invocando a `yyFlexLexer::LexerError()') si es llamada. See section Generando escßneres en C++, para informaci≤n adicional.

Estßn disponibles un n·mero de opciones para los puristas de lint que desean suprimir la aparici≤n de rutinas no necesarias en el analizador generado. Cada una de la siguientes, si se desactivan (p.ej., `%option nounput'), hace que la rutina correspondiente no aparezca en el analizador generado:

input, unput
yy_push_state, yy_pop_state, yy_top_state
yy_scan_buffer, yy_scan_bytes, yy_scan_string

(aunque `yy_push_state()' y sus amigas no aparecerßn de todas manera a menos que use `%option stack').

Consideraciones de rendimiento

El principal objetivo de dise±o de flex es que genere analizadores de alto rendimiento. Este ha sido optimizado para comportarse bien con conjuntos grandes de reglas. Aparte de los efectos sobre la velocidad del analizador con las opciones de compresi≤n de tablas `-C' anteriormente introducidas, hay un n·mero de opciones/acciones que degradan el rendimiento. Estas son, desde la mßs costosa a la menos:

REJECT
%option yylineno
contexto posterior arbitrario

conjunto de patrones que requieren retroceso
%array
%option interactive
%option always-interactive

`^' operador de comienzo de lφnea
yymore()

siendo las tres primeras bastante costosas y las dos ·ltimas bastante econ≤micas. Fφjese tambiΘn que `unput()' se implementa como una llamada de rutina que potencialmente hace bastante trabajo, mientras que `yyless()' es una macro bastante econ≤mica; asφ que si estß devolviendo alg·n texto excedente que ha analizado, use `yyless()'.

REJECT deberφa evitarse a cualquier precio cuando el rendimiento es importante. Esta es una opci≤n particularmente cara.

Es lioso deshacerse del retroceso y a menudo podrφa ser una cantidad de trabajo enorme para un analizador complicado. En principio, uno comienza utilizando la bandera `-b' para generar un archivo `lex.backup'. Por ejemplo, sobre la entrada

%%
foo        return TOK_KEYWORD;
foobar     return TOK_KEYWORD;

el fichero tiene el siguiente aspecto:

El estado #6 es no-aceptar -
 n·meros de lφnea asociados a la regla:
       2       3
 fin de transiciones: [ o ]
 transiciones de bloqueo: fin de archivo (EOF) [ \001-n  p-\177 ]

El estado #8 es no-aceptar -
 n·meros de lφnea asociados a la regla:
       3
 fin de transiciones: [ a ]
 transiciones de bloqueo: fin de archivo (EOF) [ \001-`  b-\177 ]

El estado #9 es no-aceptar -
 n·meros de lφnea asociados a la regla:
       3
 fin de transiciones: [ r ]
 transiciones de bloqueo: fin de archivo (EOF) [ \001-q  s-\177 ]

Las tablas comprimidas siempre implican un retroceso.

Las primeras lφneas nos dicen que hay un estado del analizador en el que se puede hacer una transici≤n con una `o' pero no sobre cualquier otro caracter, y que en ese estado el texto recientemente analizado no empareja con ninguna regla. El estado ocurre cuando se intenta emparejar las reglas encontradas en las lφneas 2 y 3 en el fichero de entrada. Si el analizador estß en ese estado y entoces lee cualquier cosa que no sea una `o', tendrß que retroceder para encontrar una regla que empareje. Con un poco de anßlisis uno puede ver que este debe ser el estado en el que se estß cuando se ha visto "fo". Cuando haya ocurrido, si se ve cualquier cosa que no sea una `o', el analizador tendrß que retroceder para simplemente emparejar la `f' (por la regla por defecto).

El comentario que tiene que ver con el Estado #8 indica que hay un problema cuando se analiza "foob". En efecto, con cualquier caracter que no sea una `a', el analizador tendrß que retroceder para aceptar "foo". De forma similar, el comentario para el Estado #9 tiene que ver cuando se ha analizado "fooba" y no le sigue una `r'.

El comentario final nos recuerda que no mecere la pena todo el trabajo para eliminar el retroceso de las reglas a menos que estemos usando `-Cf'`-CF', y que no hay ninguna mejora del rendimiento haciΘndolo con analizadores comprimidos.

La manera de quitar los retrocesos es a±adiendo reglas de "error":

%%
foo         return TOK_KEYWORD;
foobar      return TOK_KEYWORD;

fooba       |
foob        |
fo          {
            /* falsa alarma, realmente no es una palabra clave */
            return TOK_ID;
            }

La eliminaci≤n de retroceso en una lista de palabras clave tambiΘn puede hacerse utilizando una regla "atrßpalo-todo":

%%
foo         return TOK_KEYWORD;
foobar      return TOK_KEYWORD;

[a-z]+      return TOK_ID;

Normalmente esta es la mejor soluci≤n cuando sea adecuada.

Los mensajes sobre retrocesos tienden a aparecer en cascada. Con un conjunto complicado de reglas no es poco com·n obtener cientos de mensajes. Si uno puede descifrarlos, sin embargo, a menudo s≤lo hay que tomar una docena de reglas o algo asφ para eliminar los retrocesos (ya que es fßcil cometer una equivocaci≤n y tener una regla de error que reconozca un token vßlido. Una posible caracterφstica futura de flex serß a±adir reglas automßticamente para eliminar el retroceso).

Es importante tener en cuenta que se obtienen los beneficios de eliminar el retroceso s≤lo si elimina cada instancia del retroceso. Dejar solamente una significa que no ha ganado absolutamente nada.

El contexto posterior variable (donde la parte delantera y posterior no tienen una longitud fija) supone casi la misma pΘrdida de rendimiento que REJECT (es decir, substanciales). Asφ que cuando sea posible una regla como esta:

%%
raton|rata/(gato|perro)   correr();

es mejor escribirla asφ:

%%
raton/gato|perro          correr();
rata/gato|perro           correr();

o asφ

%%
raton|rata/gato           correr();
raton|rata/perro          correr();

Fφjese que aquφ la acci≤n especial `|' no ofrece ning·n ahorro, y puede incluso hacer las cosas peor (see section Deficiencias / Errores).

Otro ßrea donde el usuario puede incrementar el rendimiento del analizador (y una que es mßs fßcil de implementar) surge del hecho que cuanto mßs tarde se empareje un token, mßs rßpido irß el analizador. Esto es debido a que con tokens grandes el procesamiento de la mayorφa de los caracteres de entrada tiene lugar en el (corto) bucle de anßlisis mßs interno, y no tiene que ir tan a menudo a hacer el trabajo de mßs para constituir el entorno del analizador (p.ej., yytext) para la acci≤n. Recuerde el analizador para los comentarios en C:

%x comentario
%%
        int num_linea = 1;

"/*"         BEGIN(comentario);

<comentario>[^*\n]*
<comentario>"*"+[^*/\n]*
<comentario>\n             ++num_linea;
<comentario>"*"+"/"        BEGIN(INITIAL);

Esto podrφa acelerarse escribiΘndolo como:

%x comentario
%%
        int num_linea = 1;

"/*"         BEGIN(comentario);

<comentario>[^*\n]*
<comentario>[^*\n]*\n      ++num_linea;
<comentario>"*"+[^*/\n]*
<comentario>"*"+[^*/\n]*\n ++num_linea;
<comentario>"*"+"/"        BEGIN(INITIAL);

Ahora en lugar de que cada lφnea nueva requiera el procesamiento de otra regla, el reconocimiento de las lφneas nuevas se "distribuye" sobre las otras reglas para mantener el texto reconocido tan largo como sea posible. íFφjese que el a±adir reglas no ralentiza el analizador! La velocidad del analizador es independiente del n·mero de reglas o (dadas las consideraciones dadas al inicio de esta secci≤n) cußn complicadas sean las reglas respecto a operadores tales como `*' y `|'.

Un ejemplo final sobre la aceleraci≤n de un analizador: suponga que quiere analizar un fichero que contiene identificadores y palabras clave, una por lφnea y sin ning·n caracter extra±o, y reconocer todas las palabras clave. Una primera aproximaci≤n natural es:

%%
asm      |
auto     |
break    |
... etc ...
volatile |
while    /* es una palabra clave */

.|\n     /* no es una palabra clave */

Para eliminar el retroceso, introduzca una regla atrßpalo-todo:

%%
asm      |
auto     |
break    |
... etc ...
volatile |
while    /* es una palabra clave */

[a-z]+   |
.|\n     /* no es una palabra clave */

Ahora, si se garantiza que hay exßctamente una palabra por lφnea, entonces podemos reducir el n·mero total de emparejamientos por la mitad mezclando el reconocimiento de lφneas nuevas con las de los otros tokens:

%%
asm\n    |
auto\n   |
break\n  |
... etc ...
volatile\n |
while\n  /* es una palabra clave */

[a-z]+\n |
.|\n     /* no es una palabra clave */

Uno tiene que ser cuidadoso aquφ, ya que hemos reintroducido retroceso en el analizador. En particular, aunque nosotros sepamos que ahφ nunca habrßn otros caracteres en el flujo de entrada que no sean letras o lφneas nuevas, flex no puede figurarse eso, y planearß la posible necesidad de retroceder cuando haya analizado un token como "auto" y el pr≤ximo caracter sea algo distinto a una lφnea nueva o una letra. Previamente este podrφa entonces emparejar la regla "auto" y estar todo hecho, pero ahora este no tiene una regla "auto", solamente una regla "auto\n". Para eliminar la posibilidad de retroceso, podrφamos o bien duplicar todas las reglas pero sin lφnea nueva al final, o, ya que nunca esperamos encontrar tal entrada y por lo tanto ni c≤mo es clasificada, podemos introducir una regla atrßpalo-todo mßs, esta que no incluye una lφnea nueva:

%%
asm\n    |
auto\n   |
break\n  |
... etc ...
volatile\n |
while\n  /* es una palabra clave */

[a-z]+\n |
[a-z]+   |
.|\n     /* no es una palabra clave */

Compilado con `-Cf', esto es casi tan rßpido como lo que uno puede obtener de un analizador de flex para este problema en particular.

Una nota final: flex es lento cuando empareja NUL's, particularmente cuando un token contiene m·ltiples NUL's. Es mejor escribir reglas que emparejen cortas cantidades de texto si se anticipa que el texto incluirß NUL's a menudo.

Otra nota final en relaci≤n con el rendimiento: tal y como se mencion≤ en el section C≤mo se empareja la entrada, el reajuste dinßmico de yytext para acomodar tokens enormes es un proceso lento porque ahora requiere que el token (inmenso) sea reanalizado desde el principio. De esta manera si el rendimiento es vital, deberφa intentar emparejar "grandes" cantidades de texto pero no "inmensas" cantidades, donde el punto medio estß en torno a los 8K caracteres/token.

Generando escßneres en C++

flex ofrece dos maneras distintas de generar analizadores para usar con C++. La primera manera es simplemente compilar un analizador generado por flex usando un compilador de C++ en lugar de un compilador de C. No deberφa encontrarse ante ning·n error de compilaci≤n (por favor informe de cualquier error que encuentre a la direcci≤n de correo electr≤nico dada en el section Autor). Puede entonces usar c≤digo C++ en sus acciones de las reglas en lugar de c≤digo C. Fφjese que la fuente de entrada por defecto para su analizador permanece como yyin, y la repetici≤n por defecto se hace a·n a yyout. Ambos permanecen como variables `FILE *' y no como flujos de C++.

TambiΘn puede utilizar flex para generar un analizador como una clase de C++, utilizando la opci≤n `-+' (o, equivalentemente, `%option c++'), que se especifica automßticamente si el nombre del ejecutable de flex finaliza con un `+', tal como flex++. Cuando se usa esta opci≤x, flex establece por defecto la generaci≤n del analizador al fichero `lex.yy.cc' en vez de `lex.yy.c'. El analizador generado incluye el fichero de cabecera `FlexLexer.h', que define el interfaz con las dos clases de C++.

La primera clase, FlexLexer, ofrece una clase base abstracta definiendo la interfaz a la clase del analizador general. Este provee las siguientes funciones miembro:

`const char* YYText()'
retorna el texto del token reconocido mßs recientemente, el equivalente a yytext.
`int YYLeng()'
retorna la longitud del token reconocido mßs recientemente, el equivalente a yyleng.
`int lineno() const'
retorna el n·mero de lφnea de entrada actual (ver `%option yylineno'), ≤ 1 si no se us≤ `%option yylineno'.
`void set_debug( int flag )'
activa la bandera de depuraci≤n para el analizador, equivalente a la asignaci≤n de yy_flex_debug (see section Opciones). Fφjese que debe construir el analizador utilizando `%option debug' para incluir informaci≤n de depuraci≤n en este.
`int debug() const'
retorna el estado actual de la bandera de depuraci≤n.

TambiΘn se proveen funciones miembro equivalentes a `yy_switch_to_buffer()', `yy_create_buffer()' (aunque el primer argumento es un puntero a objeto `istream*' y no un `FILE*'), `yy_flush_buffer()', `yy_delete_buffer()', y `yyrestart()' (de nuevo, el primer argumento es un puntero a objeto `istream*').

La segunda clase definida en `FlexLexer.h' es yyFlexLexer, que se deriva de FlexLexer. Esta define las siguientes funciones miembro adicionales:

`yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 )'
construye un objeto yyFlexLexer usando los flujos dados para la entrada y salida. Si no se especifica, los flujos se establecen por defecto a cin y cout, respectivamente.
`virtual int yylex()'
hace el mismo papel que `yylex()' en los analizadores de flex ordinarios: analiza el flujo de entrada, consumiendo tokens, hasta que la acci≤n de una regla retorne un valor. Si usted deriva una subclase S a partir de yyFlexLexer y quiere acceder a las funciones y variables miembro de S dentro de `yylex()', entonces necesita utilizar `%option yyclass="S"' para informar a flex que estarß utilizando esa subclase en lugar de yyFlexLexer. Es este caso, en vez de generar `yyFlexLexer::yylex()', flex genera `S::yylex()' (y tambiΘn genera un substituto `yyFlexLexer::yylex()' que llama a `yyFlexLexer::LexerError()' si se invoca).
`virtual void switch_streams(istream* new_in = 0, ostream* new_out = 0)'
reasigna yyin a new_in (si no es nulo) e yyout a new_out (idem), borrando el buffer de entrada anterior si se reasigna yyin.
`int yylex( istream* new_in, ostream* new_out = 0 )'
primero conmuta el flujo de entrada via `switch_streams( new_in, new_out )' y entonces retorna el valor de `yylex()'.

Ademßs, yyFlexLexer define las siguientes funciones virtuales protegidas que puede redefinir en clases derivadas para adaptar el analizador:

`virtual int LexerInput( char* buf, int max_size )'
lee hasta `max_size' caracteres en buf y devuelve el n·mero de caracteres leφdos. Para indicar el fin-de-la-entrada, devuelve 0 caracteres. Fφjese que los analizadores "interactivos" (ver las banderas `-B' y `-I') definen la macro YY_INTERACTIVE. Si usted redefine LexerInput() y necesita tomar acciones distintas dependiendo de si el analizador estß analizando una fuente de entrada interactivo o no, puede comprobar la presencia de este nombre mediante `#ifdef'.
`virtual void LexerOutput( const char* buf, int size )'
escribe a la salida size caracteres desde el buffer buf, que, mientras termine en NUL, puede contener tambiΘn NUL's "internos" si las reglas del analizador pueden emparejar texto con NUL's dentro de este.
`virtual void LexerError( const char* msg )'
informa con un mensaje de error fatal. La versi≤n por defecto de esta funci≤n escribe el mensaje al flujo cerr y finaliza.

Fφjese que un objeto yyFlexLexer contiene su estado de anßlisis completo. Asφ puede utilizar tales objetos para crear analizadore reentrantes. Puede hacer varias instancias de la misma clase yyFlexLexer, y puede combinar varias clases de analizadores en C++ conjuntamente en el mismo programa usando la opci≤n `-P' comentada anteriormente.

Finalmente, note que la caracterφstica `%array' no estß disponible en clases de analizadores en C++; debe utilizar `%pointer' (por defecto).

Aquφ hay un ejemplo de un analizador en C++ simple:

// Un ejemplo del uso de la clase analizador en C++ de flex.

%{
int mylineno = 0;
%}

string  \"[^\n"]+\"

ws      [ \t]+

alpha   [A-Za-z]
dig     [0-9]
name    ({alpha}|{dig}|\$)({alpha}|{dig}|[_.\-/$])*
num1    [-+]?{dig}+\.?([eE][-+]?{dig}+)?
num2    [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)?
number  {num1}|{num2}

%%

{ws}    /* evita los espacios en blanco y tabuladores */

"/*"    {
        int c;

        while((c = yyinput()) != 0)
            {
            if(c == '\n')
                ++mylineno;

            else if(c == '*')
                {
                if((c = yyinput()) == '/')
                    break;
                else
                    unput(c);
                }
            }
        }

{number}  cout << "n·mero " << YYText() << '\n';

\n        mylineno++;

{name}    cout << "nombre " << YYText() << '\n';

{string}  cout << "cadena " << YYText() << '\n';

%%

int main( int /* argc */, char** /* argv */ )
    {
    FlexLexer* lexer = new yyFlexLexer;
    while(lexer->yylex() != 0)
        ;
    return 0;
    }

Si desea crear varias (diferentes) clases analizadoras, use la bandera `-P' (o la opci≤n `prefix=') para renombrar cada yyFlexLexer a alg·n otro xxFlexLexer. Entonces puede incluir `<FlexLexer.h>' en los otros ficheros fuente una vez por clase analizadora, primero renombrando yyFlexLexer como se presenta a continuaci≤n:

#undef yyFlexLexer
#define yyFlexLexer xxFlexLexer
#include <FlexLexer.h>

#undef yyFlexLexer
#define yyFlexLexer zzFlexLexer
#include <FlexLexer.h>

si, por ejemplo, usted utiliz≤ `%option prefix="xx"' para uno de sus analizadores y `%option prefix="zz"' para el otro.

IMPORTANTE: la forma actual de la clase analizadora es experimental y podrφa cambiar considerablemente entre versiones principales.

Incompatibilidades con lex y POSIX

flex es una reescritura de la herramienta lex del Unix de AT&T (aunque las dos implementaciones no comparten ning·n c≤digo), con algunas extensiones e incompatibilidades, de las que ambas conciernen a aquellos que desean escribir analizadores aceptables por cualquier implementaci≤n. Flex sigue completamente la especificaci≤n POSIX de lex, excepto que cuando se utiliza `%pointer' (por defecto), una llamada a `unput()' destruye el contenido de yytext, que va en contra de la especificaci≤n POSIX.

En esta secci≤n comentaremos todas las ßreas conocidas de incompatibilidades entre flex, lex de AT&T, y la especificaci≤n POSIX.

La opci≤n `-l' de flex activa la mßxima compatibilidad con la implementaci≤n original de lex de AT&T, con el coste de una mayor pΘrdida de rendimiento en el analizador generado. Indicamos mßs abajo quΘ incompatibilidades pueden superarse usando la opci≤n `-l'.

flex es totalmente compatible con lex con las siguientes excepciones:

Las siguientes propiedades de flex no se incluyen en lex o la especificaci≤n POSIX:

analizadores en C++
%option
ßmbitos de condiciones de arranque
pilas de condiciones de arranque
analizadores interactivos/no-interactivos
yy_scan_string() y sus amigas
yyterminate()
yy_set_interactive()
yy_set_bol()
YY_AT_BOL()
<<EOF>>
<*>
YY_DECL
YY_START
YY_USER_ACTION
YY_USER_INIT
directivas #line
%{}'s alrededor de acciones
varias acciones en una lφnea

mßs casi todas las banderas de flex. La ·ltima propiedad en la lista se refiere al hecho de que con flex puede poner varias acciones en la misma lφnea, sepradas con punto y coma, mientras que con lex, lo siguiente

foo    handle_foo(); ++num_foos_seen;

se trunca (sorprendentemente) a

foo    handle_foo();

flex no trunca la acci≤n. Las acciones que no se encierran en llaves simplemente se terminan al final de la lφnea.

Diagn≤sticos

`aviso, la regla no se puede aplicar'
indica que la regla dada no puede emparejarse porque sigue a otras reglas que siempre emparejarßn el mismo texto que el de esta. Por ejemplo, en el siguiente ejemplo "foo" no puede emparejarse porque viene despuΘs de una regla "atrßpalo-todo" para identificadores:
[a-z]+    obtuvo_identificador();
foo       obtuvo_foo();
El uso de REJECT en un analizador suprime este aviso.
`aviso, se ha especificado la opci≤n -s pero se puede aplicar la regla por defecto'
significa que es posible (tal vez ·nicamente en una condici≤n de arranque en particular) que la regla por defecto (emparejar cualquier caracter simple) sea la ·nica que emparejarß una entrada particular. Ya que se indic≤ `-s', presumiblemente esto no es lo que se pretendφa.
`definici≤n no definida reject_used_but_not_detected'
`definici≤n no definida yymore_used_but_not_detected'
Estos errores pueden suceder en tiempo de compilaci≤n. Indican que el analizador usa REJECT o `yymore()' pero que flex fall≤ en darse cuenta del hecho, queriendo decir que flex analiz≤ las dos primeras secciones buscando apariciones de estas acciones y fall≤ en encontrar alguna, pero que de alg·n modo se le han colado (por medio de un archivo #include, por ejemplo). Use `%option reject'`%option yymore' para indicar a flex que realmente usa esta funcionalidad.
`flex scanner jammed'
un analizador compilado con `-s' ha encontrado una cadena de entrada que no fue reconocida por niguna de sus reglas. Este error puede suceder tambiΘn debido a problemas internos.
`token too large, exceeds YYLMAX'
su analizador usa `%array' y una de sus reglas reconoci≤ una cadena mßs grande que la constante YYLMAX (8K bytes por defecto). Usted puede incrementar el valor haciendo un #define YYLMAX en la secci≤n de definiciones de su entrada de flex.
`el analizador requiere la opci≤n -8 para poder usar el carßcter 'x''
La especificaci≤n de su analizador incluye el reconocimiento del caracter de 8-bits x y no ha especificado la bandera -8, y su analizador por defecto estß a 7-bits porque ha usado las opciones `-Cf'`-CF' de compresi≤n de tablas. See section Opciones, el comentario de la bandera `-7' para los detalles.
`flex scanner push-back overflow'
usted utiliz≤ `unput()' para devolver tanto texto que el buffer del analizador no pudo mantener el texto devuelto y el token actual en yytext. Idealmente el analizador deberφa ajustar dinßmicamente el buffer en este caso, pero actualmente no lo hace.
`input buffer overflow, can't enlarge buffer because scanner uses REJECT'
el analizador estaba intentando reconocer un token extremadamente largo y necesit≤ expandir el buffer de entrada. Esto no funciona con analizadores que usan REJECT.
`fatal flex scanner internal error--end of buffer missed'
Esto puede suceder en un analizador que se reintroduce despuΘs de que un long-jump haya saltado fuera (o sobre) el registro de activaci≤n del analizador. Antes de reintroducir el analizador, use:
yyrestart( yyin );
o, como se coment≤ en el section Generando escßneres en C++, cambie y use el analizador como clase de C++.
`too many start conditions in <> construct!'
ha listado mßs condiciones de arranque en una construcci≤n <> que las que existen (asφ que tuvo que haber listado al menos una de ellas dos veces).

Ficheros

`-lfl'
librerφa con la que los analizadores deben enlazarse.
`lex.yy.c'
analizador generado (llamado `lexyy.c' en algunos sistemas).
`lex.yy.cc'
clase generada en C++ con el analizador, cuando se utiliza `-+'.
`<FlexLexer.h>'
fichero de cabecera definiendo la clase base del analizador en C++, FlexLexer, y su clase derivada, yyFlexLexer.
`flex.skl'
esqueleto del analizador. Este fichero se utiliza ·nicamente cuando se construye flex, no cuando flex se ejecuta.
`lex.backup'
informaci≤n de los retrocesos para la bandera `-b' (llamada `lex.bck' en algunos sistemas).

Deficiencias / Errores

Algunos patrones de contexto posterior no pueden reconocerse correctamente y generan mensajes de aviso ("contexto posterior peligroso"). Estos son patrones donde el final de la primera parte de la regla reconoce el comienzo de la segunda parte, tal como "zx*/xy*", donde el 'x*' reconoce la `x' al comienzo del contexto posterior. (Fφjese que el borrador de POSIX establece que el texto reconocido por tales patrones no estß definido.)

Para algunas reglas de contexto posterior, partes que son de hecho de longitud fija no se reconocen como tales, resultando en la pΘrdida de rendimiento mencionada anteriormente. En particular, las partes que usan `|' o {n} (tales como "foo{3}") siempre se consideran de longitud variable.

La combinaci≤n de contexto posterior con la acci≤n especial `|' puede producir que el contexto posterior fijo se convierta en contexto posterior variable que es mßs caro. Por ejemplo, en lo que viene a continuaci≤n:

%%
abc      |
xyz/def

El uso de `unput()' invalida yytext e yyleng, a menos que se use la directiva `%array' o la opci≤n `-l'.

La concordancia de patrones de NUL's es substancialmente mßs lento que el reconocimiento de otros caracteres.

El ajuste dinßmico del buffer de entrada es lento, ya que conlleva el reanßlisis de todo el texto reconocido hasta entonces por el (generalmente enorme) token actual.

Debido al uso simultßneo de buffers de entrada y lecturas por adelantado, no puede entremezclar llamadas a rutinas de <stdio.h>, tales como, por ejemplo, `getchar()', con reglas de flex y esperar que funcione. Llame a `input()' en su lugar.

La totalidad de las entradas de la tabla listada por la bandera `-v' excluye el n·mero de entradas en la tabla necesarias para determinar quΘ regla ha sido emparejada. El n·mero de entradas es igual al n·mero de estados del DFA si el analizador no usa REJECT, y algo mayor que el n·mero de estados si se usa.

REJECT no puede usarse con las opciones `-f'`-F'.

El algoritmo interno de flex necesita documentaci≤n.

Ver tambiΘn

lex(1), yacc(1), sed(1), awk(1).

John Levine, Tony Mason, and Doug Brown: Lex & Yacc, O'Reilly and Associates. EstΘ seguro de obtener la 2¬ edici≤n.

M. E. Lesk and E. Schmidt, LEX - Lexical Analyzer Generator

Alfred Aho, Ravi Sethi and Jeffrey Ullman: Compilers: Principles, Techniques and Tools; Addison-Wesley (1986) --Edici≤n en castellano: Compiladores: Principios, TΘcnicas y Herramientas, Addison-Wesley Iberoamericana, S.A. (1990). Describe las tΘcnicas de concordancia de patrones usadas por flex (aut≤mata finito determinista).

Autor

Vern Paxson, con la ayuda de muchas ideas e inspiraci≤n de Van Jacobson. Versi≤n original por Jef Poskanzer. La representaci≤n de tablas rßpidas es una implementaci≤n parcial de un dise±o hecho por Van Jacobson. La implementaci≤n fue hecha por Kevin Gong y Vern Paxson.

Agradecimientos a los muchos flex beta-testers, feedbackers, y contribuidores, especialmente a Francois Pinard, Casey Leedom, Robert Abramovitz, Stan Adermann, Terry Allen, David Barker-Plummer, John Basrai, Neal Becker, Nelson H.F. Beebe, `benson@odi.com', Karl Berry, Peter A. Bigot, Simon Blanchard, Keith Bostic, Frederic Brehm, Ian Brockbank, Kin Cho, Nick Christopher, Brian Clapper, J.T. Conklin, Jason Coughlin, Bill Cox, Nick Cropper, Dave Curtis, Scott David Daniels, Chris G. Demetriou, Theo Deraadt, Mike Donahue, Chuck Doucette, Tom Epperly, Leo Eskin, Chris Faylor, Chris Flatters, Jon Forrest, Jeffrey Friedl, Joe Gayda, Kaveh R. Ghazi, Wolfgang Glunz, Eric Goldman, Christopher M. Gould, Ulrich Grepel, Peer Griebel, Jan Hajic, Charles Hemphill, NORO Hideo, Jarkko Hietaniemi, Scott Hofmann, Jeff Honig, Dana Hudes, Eric Hughes, John Interrante, Ceriel Jacobs, Michal Jaegermann, Sakari Jalovaara, Jeffrey R. Jones, Henry Juengst, Klaus Kaempf, Jonathan I. Kamens, Terrence O Kane, Amir Katz, `ken@ken.hilco.com', Kevin B. Kenny, Steve Kirsch, Winfried Koenig, Marq Kole, Ronald Lamprecht, Greg Lee, Rohan Lenard, Craig Leres, John Levine, Steve Liddle, David Loffredo, Mike Long, Mohamed el Lozy, Brian Madsen, Malte, Joe Marshall, Bengt Martensson, Chris Metcalf, Luke Mewburn, Jim Meyering, R. Alexander Milowski, Erik Naggum, G.T. Nicol, Landon Noll, James Nordby, Marc Nozell, Richard Ohnemus, Karsten Pahnke, Sven Panne, Roland Pesch, Walter Pelissero, Gaumond Pierre, Esmond Pitt, Jef Poskanzer, Joe Rahmeh, Jarmo Raiha, Frederic Raimbault, Pat Rankin, Rick Richardson, Kevin Rodgers, Kai Uwe Rommel, Jim Roskind, Alberto Santini, Andreas Scherer, Darrell Schiebel, Raf Schietekat, Doug Schmidt, Philippe Schnoebelen, Andreas Schwab, Larry Schwimmer, Alex Siegel, Eckehard Stolz, Jan-Erik Strvmquist, Mike Stump, Paul Stuart, Dave Tallman, Ian Lance Taylor, Chris Thewalt, Richard M. Timoney, Jodi Tsai, Paul Tuinenga, Gary Weik, Frank Whaley, Gerhard Wilhelms, Kent Williams, Ken Yap, Ron Zellar, Nathan Zelle, David Zuhn, y aquellos cuyos nombres han caφdo bajo mis escasas dotes de archivador de correo pero cuyas contribuciones son apreciadas todas por igual.

Agradecimientos a Keith Bostic, Jon Forrest, Noah Friedman, John Gilmore, Craig Leres, John Levine, Bob Mulcahy, G.T. Nicol, Francois Pinard, Rich Salz, y a Richard Stallman por la ayuda con diversos quebraderos de cabeza con la distribuci≤n.

Agradecimientos a Esmond Pitt y Earle Horton por el soporte de caracteres de 8-bits; a Benson Margulies y a Fred Burke por el soporte de C++; a Kent Williams y a Tom Epperly por el soporte de la clase de C++; a Ove Ewerlid por el soporte de NUL's; y a Eric Hughes por el soporte de m·ltiples buffers.

Este trabajo fue hecho principalmente cuando yo estaba con el Grupo de Sistemas de Tiempo Real en el Lawrence Berkeley Laboratory en Berkeley, CA. Muchas gracias a todos allφ por el apoyo que recibφ.

Enviar comentarios a @email{vern@ee.lbl.gov, Vern Paxson}.

Sobre esta traducci≤n enviar comentarios a @email{alu1415@csi.ull.es, Adrißn PΘrez Jorge}.

═ndice

<

  • <*>
  • <<EOF>>
  • a

  • acciones
  • arranque, condiciones de
  • autores
  • b

  • BEGIN
  • buffers de entrada, m·ltiples
  • c

  • C++, generaci≤n de escßneres en
  • cadenas literales
  • clase analizador, ejemplo de uso
  • clase de caracteres
  • clase de caracteres negada
  • clases de C++, generadores como
  • concatenaci≤n
  • condiciones de arranque
  • contexto posterior
  • contexto posterior peligroso
  • contexto posterior variable
  • contexto, introducci≤n de
  • c≤digo, secci≤n de
  • d

  • debug
  • deficiencias
  • definiciones, expansi≤n de
  • definiciones, seccion de
  • desbordamiento del buffer
  • descripci≤n
  • diagn≤sticos
  • e

  • ECHO
  • ejemplo, uso de la clase analizador
  • ejemplos simples
  • eliminaci≤n del retroceso
  • emparejamiento de la entrada
  • entrada de flex, formato de la
  • entrada, control de la fuente de
  • entrada, emparejamiento de la
  • entrada, m·ltiples buffers de
  • error, mensajes de
  • errores
  • escßner generado
  • escßneres en C++, generaci≤n de
  • expansi≤n de definiciones
  • expresiones regulares
  • f

  • fichero de entrada de flex
  • ficheros
  • fin-de-fichero, reglas de
  • flex, introducci≤n
  • FLEX_SCANNER
  • formato del fichero
  • fuente de entrada, control de la
  • g

  • generaci≤n de escßneres en C++
  • i

  • incompatibilidades
  • input
  • interfaz con yacc
  • introducci≤n
  • l

  • lex de AT&T
  • lex de POSIX
  • lex, incompatibilidades
  • lex.yy.c
  • LexerError
  • LexerInput
  • LexerOutput
  • lineno
  • m

  • macros miscelßneas
  • mensajes de error
  • mini-escßneres
  • m·ltiples buffers de entrada
  • o

  • opciones
  • operador ^, precedencia
  • operador {}, precedencia del
  • p

  • patrones
  • POSIX, incompatibilidades
  • precedencia
  • r

  • rango de caracteres
  • reconocimiento de la entrada
  • referencias
  • reglas de fin-de-fichero
  • reglas, secci≤n de
  • REJECT
  • rendimiento, consideraciones
  • retroceso
  • retroceso, eliminaci≤n
  • s

  • seccion de definiciones
  • secciones
  • secci≤n de c≤digo
  • secci≤n de reglas
  • set_debug
  • switch_streams
  • t

  • tokens demasiado largos
  • u

  • unput
  • v

  • valores disponibles
  • variables disponibles
  • y

  • yacc, interfaz con
  • YY_AT_BOL
  • YY_BREAK
  • yy_create_buffer
  • YY_CURRENT_BUFFER, YY_CURRENT_BUFFER
  • yy_delete_buffer
  • YY_FLEX_MAJOR_VERSION
  • YY_FLEX_MINOR_VERSION
  • yy_flush_buffer
  • YY_FLUSH_BUFFER
  • YY_INPUT
  • yy_new_buffer
  • yy_pop_state
  • yy_push_state
  • yy_restart
  • yy_scan_buffer, yy_scan_buffer
  • yy_scan_bytes, yy_scan_bytes
  • yy_scan_string, yy_scan_string
  • yy_set_bol
  • yy_set_interactive
  • YY_START, YY_START
  • yy_switch_to_buffer
  • yy_top_state
  • YY_USER_ACTION
  • YY_USER_INIT
  • yyFlexLexer
  • yyin
  • yyleng
  • YYLeng
  • yyless
  • yylex, yylex, yylex
  • yylineno
  • yyout
  • yyrestart
  • YYSTATE
  • yyterminate
  • YYText
  • yytext
  • yywrap

  • This document was generated on 25 May 1999 using the texi2html translator version 1.51.